remove debug
[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>
7ad3837a 30#include <ltt/marker-desc.h>
f95bc830 31#include <stdio.h>
b3fd4c02 32#include <string.h>
dc877563 33
7df20ca4 34/* Comment :
35 * Mathieu Desnoyers
36 * usertrace is there only to be able to update the current CPU of the
37 * usertraces when there is a schedchange. it is a way to link the ProcessState
38 * to the associated usertrace. Link only created upon thread creation.
39 *
40 * The cpu id is necessary : it gives us back the current ProcessState when we
41 * are considering data from the usertrace.
42 */
43
e8f2280c 44#define PREALLOCATED_EXECUTION_STACK 10
45
eed2ef37 46/* Facilities Quarks */
47
48GQuark
49 LTT_FACILITY_KERNEL,
f5d7967f 50 LTT_FACILITY_KERNEL_ARCH,
86c32a8f 51 LTT_FACILITY_LIST,
b3fd4c02 52 LTT_FACILITY_FS,
27811799 53 LTT_FACILITY_USER_GENERIC,
54 LTT_FACILITY_BLOCK;
eed2ef37 55
56/* Events Quarks */
57
58GQuark
59 LTT_EVENT_SYSCALL_ENTRY,
60 LTT_EVENT_SYSCALL_EXIT,
61 LTT_EVENT_TRAP_ENTRY,
62 LTT_EVENT_TRAP_EXIT,
63 LTT_EVENT_IRQ_ENTRY,
64 LTT_EVENT_IRQ_EXIT,
faf074a3 65 LTT_EVENT_SOFT_IRQ_ENTRY,
66 LTT_EVENT_SOFT_IRQ_EXIT,
86c32a8f 67 LTT_EVENT_SCHED_SCHEDULE,
68 LTT_EVENT_PROCESS_FORK,
69 LTT_EVENT_KTHREAD_CREATE,
70 LTT_EVENT_PROCESS_EXIT,
71 LTT_EVENT_PROCESS_FREE,
b3fd4c02 72 LTT_EVENT_EXEC,
86c32a8f 73 LTT_EVENT_PROCESS_STATE,
c3b3b60b 74 LTT_EVENT_STATEDUMP_END,
80e0221b 75 LTT_EVENT_FUNCTION_ENTRY,
76 LTT_EVENT_FUNCTION_EXIT,
27811799 77 LTT_EVENT_THREAD_BRAND,
78 LTT_EVENT_REQUEST_ISSUE,
38b73700 79 LTT_EVENT_REQUEST_COMPLETE,
80 LTT_EVENT_LIST_INTERRUPT;
eed2ef37 81
82/* Fields Quarks */
83
84GQuark
85 LTT_FIELD_SYSCALL_ID,
86 LTT_FIELD_TRAP_ID,
87 LTT_FIELD_IRQ_ID,
faf074a3 88 LTT_FIELD_SOFT_IRQ_ID,
f63ebe51 89 LTT_FIELD_PREV_PID,
90 LTT_FIELD_NEXT_PID,
91 LTT_FIELD_PREV_STATE,
eed2ef37 92 LTT_FIELD_PARENT_PID,
93 LTT_FIELD_CHILD_PID,
f4b88a7d 94 LTT_FIELD_PID,
fcc08e1e 95 LTT_FIELD_TGID,
f63ebe51 96 LTT_FIELD_CHILD_TGID,
b3fd4c02 97 LTT_FIELD_FILENAME,
98 LTT_FIELD_NAME,
e62e7f3a 99 LTT_FIELD_TYPE,
b3fd4c02 100 LTT_FIELD_MODE,
101 LTT_FIELD_SUBMODE,
302efbad 102 LTT_FIELD_STATUS,
80e0221b 103 LTT_FIELD_THIS_FN,
27811799 104 LTT_FIELD_CALL_SITE,
105 LTT_FIELD_MINOR,
106 LTT_FIELD_MAJOR,
38b73700 107 LTT_FIELD_OPERATION,
43fb1d98 108 LTT_FIELD_ACTION;
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,
60c5092c 1635 LTT_FACILITY_KERNEL_ARCH,
9ec91d57 1636 LTT_EVENT_SYSCALL_ENTRY,
eda0fe5f 1637 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
6418800d 1638 NULL, NULL, &hooks)) {
80e0221b 1639
8979f265 1640// th = lttv_trace_hook_get_first(&th);
1641//
d3a66443 1642// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
8979f265 1643// nb = ltt_type_element_number(t);
1644//
8979f265 1645// name_tables->syscall_names = g_new(GQuark, nb);
1646// name_tables->nb_syscalls = nb;
1647//
1648// for(i = 0 ; i < nb ; i++) {
1649// name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1650// if(!name_tables->syscall_names[i]) {
1651// GString *string = g_string_new("");
1652// g_string_printf(string, "syscall %u", i);
1653// name_tables->syscall_names[i] = g_quark_from_string(string->str);
1654// g_string_free(string, TRUE);
1655// }
1656// }
1657
1658 name_tables->syscall_names = g_new(GQuark, 256);
1659 for(i = 0 ; i < 256 ; i++) {
1660 g_string_printf(fe_name, "syscall %d", i);
1661 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
80e0221b 1662 }
80e0221b 1663 } else {
1664 name_tables->syscall_names = NULL;
1665 name_tables->nb_syscalls = 0;
1666 }
032ba5da 1667 lttv_trace_hook_remove_all(&hooks);
285468d4 1668
e1de4b54 1669 if(!lttv_trace_find_hook(tcs->parent.t,
60c5092c 1670 LTT_FACILITY_KERNEL_ARCH,
eed2ef37 1671 LTT_EVENT_TRAP_ENTRY,
6418800d 1672 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
1673 NULL, NULL, &hooks)) {
eed2ef37 1674
8979f265 1675// th = lttv_trace_hook_get_first(&th);
1676//
d3a66443 1677// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
8979f265 1678// //nb = ltt_type_element_number(t);
1679//
8979f265 1680// name_tables->trap_names = g_new(GQuark, nb);
1681// for(i = 0 ; i < nb ; i++) {
1682// name_tables->trap_names[i] = g_quark_from_string(
1683// ltt_enum_string_get(t, i));
1684// }
80e0221b 1685
80e0221b 1686 name_tables->nb_traps = 256;
1687 name_tables->trap_names = g_new(GQuark, 256);
1688 for(i = 0 ; i < 256 ; i++) {
1689 g_string_printf(fe_name, "trap %d", i);
1690 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1691 }
1692 } else {
1693 name_tables->trap_names = NULL;
1694 name_tables->nb_traps = 0;
1695 }
032ba5da 1696 lttv_trace_hook_remove_all(&hooks);
b445142a 1697
285468d4 1698 if(!lttv_trace_find_hook(tcs->parent.t,
60c5092c 1699 LTT_FACILITY_KERNEL,
e1de4b54 1700 LTT_EVENT_IRQ_ENTRY,
6418800d 1701 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
1702 NULL, NULL, &hooks)) {
80e0221b 1703
80e0221b 1704 /*
1705 name_tables->irq_names = g_new(GQuark, nb);
1706 for(i = 0 ; i < nb ; i++) {
1707 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1708 }
1709 */
1710
6214c229 1711 name_tables->nb_irqs = 256;
80e0221b 1712 name_tables->irq_names = g_new(GQuark, 256);
1713 for(i = 0 ; i < 256 ; i++) {
1714 g_string_printf(fe_name, "irq %d", i);
1715 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1716 }
1717 } else {
6214c229 1718 name_tables->nb_irqs = 0;
80e0221b 1719 name_tables->irq_names = NULL;
1720 }
032ba5da 1721 lttv_trace_hook_remove_all(&hooks);
faf074a3 1722 /*
1723 name_tables->soft_irq_names = g_new(GQuark, nb);
1724 for(i = 0 ; i < nb ; i++) {
1725 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1726 }
1727 */
1728
6214c229 1729 name_tables->nb_softirqs = 256;
faf074a3 1730 name_tables->soft_irq_names = g_new(GQuark, 256);
1731 for(i = 0 ; i < 256 ; i++) {
1732 g_string_printf(fe_name, "softirq %d", i);
1733 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1734 }
6418800d 1735 g_array_free(hooks, TRUE);
faf074a3 1736
b445142a 1737 g_string_free(fe_name, TRUE);
1738}
1739
1740
f95bc830 1741static void
1742get_name_tables(LttvTraceState *tcs)
1743{
1744 LttvNameTables *name_tables;
1745
1746 LttvAttributeValue v;
1747
1748 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1749 LTTV_POINTER, &v);
1750 g_assert(*(v.v_pointer) != NULL);
1751 name_tables = (LttvNameTables *)*(v.v_pointer);
eed2ef37 1752 //tcs->eventtype_names = name_tables->eventtype_names;
f95bc830 1753 tcs->syscall_names = name_tables->syscall_names;
7cd289b0 1754 tcs->nb_syscalls = name_tables->nb_syscalls;
f95bc830 1755 tcs->trap_names = name_tables->trap_names;
5e96e7e3 1756 tcs->nb_traps = name_tables->nb_traps;
f95bc830 1757 tcs->irq_names = name_tables->irq_names;
faf074a3 1758 tcs->soft_irq_names = name_tables->soft_irq_names;
6214c229 1759 tcs->nb_irqs = name_tables->nb_irqs;
1760 tcs->nb_softirqs = name_tables->nb_softirqs;
f95bc830 1761}
1762
1763
b445142a 1764static void
1765free_name_tables(LttvTraceState *tcs)
1766{
f95bc830 1767 LttvNameTables *name_tables;
1768
1769 LttvAttributeValue v;
1770
1771 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1772 LTTV_POINTER, &v);
1773 name_tables = (LttvNameTables *)*(v.v_pointer);
1774 *(v.v_pointer) = NULL;
1775
eed2ef37 1776 // g_free(name_tables->eventtype_names);
285468d4 1777 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1778 if(name_tables->trap_names) g_free(name_tables->trap_names);
1779 if(name_tables->irq_names) g_free(name_tables->irq_names);
1780 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1781 if(name_tables) g_free(name_tables);
b445142a 1782}
dc877563 1783
15b3d537 1784#ifdef HASH_TABLE_DEBUG
1785
1786static void test_process(gpointer key, gpointer value, gpointer user_data)
1787{
1788 LttvProcessState *process = (LttvProcessState *)value;
1789
1790 /* Test for process corruption */
1791 guint stack_len = process->execution_stack->len;
1792}
1793
1794static void hash_table_check(GHashTable *table)
1795{
1796 g_hash_table_foreach(table, test_process, NULL);
1797}
1798
1799
1800#endif
1801
d3d99fde 1802/* clears the stack and sets the state passed as argument */
1803static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1804{
1805 g_array_set_size(cpust->mode_stack, 1);
1806 ((GQuark *)cpust->mode_stack->data)[0] = state;
1807}
1808
1809static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1810{
1811 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1812 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1813}
1814
1815static void cpu_pop_mode(LttvCPUState *cpust)
1816{
0c0168a8 1817 if(cpust->mode_stack->len <= 1)
d3d99fde 1818 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1819 else
1820 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1821}
15b3d537 1822
5e563da0 1823/* clears the stack and sets the state passed as argument */
27811799 1824static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
1825{
1826 g_array_set_size(bdevst->mode_stack, 1);
1827 ((GQuark *)bdevst->mode_stack->data)[0] = state;
1828}
1829
1830static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
1831{
1832 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
1833 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
1834}
1835
1836static void bdev_pop_mode(LttvBdevState *bdevst)
1837{
0c0168a8 1838 if(bdevst->mode_stack->len <= 1)
27811799 1839 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
1840 else
1841 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
1842}
1843
5e563da0 1844static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
1845{
1846 g_array_set_size(irqst->mode_stack, 1);
1847 ((GQuark *)irqst->mode_stack->data)[0] = state;
1848}
1849
1850static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
1851{
1852 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
1853 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
1854}
1855
1856static void irq_pop_mode(LttvIRQState *irqst)
1857{
0c0168a8 1858 if(irqst->mode_stack->len <= 1)
5e563da0 1859 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
1860 else
1861 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
1862}
1863
b445142a 1864static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 1865 guint state_id)
dc877563 1866{
b445142a 1867 LttvExecutionState *es;
348c6ba8 1868
348c6ba8 1869 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
ae3d0f50 1870 guint cpu = tfs->cpu;
15b3d537 1871
1872#ifdef HASH_TABLE_DEBUG
1873 hash_table_check(ts->processes);
1874#endif
348c6ba8 1875 LttvProcessState *process = ts->running_process[cpu];
dc877563 1876
b445142a 1877 guint depth = process->execution_stack->len;
dc877563 1878
e05fc742 1879 process->execution_stack =
1880 g_array_set_size(process->execution_stack, depth + 1);
1881 /* Keep in sync */
1882 process->state =
1883 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1884
b445142a 1885 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1886 es->t = t;
1887 es->n = state_id;
1888 es->entry = es->change = tfs->parent.timestamp;
80e0221b 1889 es->cum_cpu_time = ltt_time_zero;
b445142a 1890 es->s = process->state->s;
1891 process->state = es;
dc877563 1892}
1893
b49e54b4 1894/* pop state
1895 * return 1 when empty, else 0 */
1896int lttv_state_pop_state_cleanup(LttvProcessState *process,
80e0221b 1897 LttvTracefileState *tfs)
b49e54b4 1898{
b49e54b4 1899 guint depth = process->execution_stack->len;
1900
1901 if(depth == 1){
1902 return 1;
1903 }
1904
1905 process->execution_stack =
1906 g_array_set_size(process->execution_stack, depth - 1);
1907 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1908 depth - 2);
1909 process->state->change = tfs->parent.timestamp;
80e0221b 1910
1911 return 0;
b49e54b4 1912}
dc877563 1913
b445142a 1914static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 1915{
ae3d0f50 1916 guint cpu = tfs->cpu;
348c6ba8 1917 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1918 LttvProcessState *process = ts->running_process[cpu];
dc877563 1919
f95bc830 1920 guint depth = process->execution_stack->len;
dc877563 1921
3d27549e 1922 if(process->state->t != t){
00e74b69 1923 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 1924 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 1925 g_info("process state has %s when pop_int is %s\n",
80e0221b 1926 g_quark_to_string(process->state->t),
1927 g_quark_to_string(t));
7b5f6cf1 1928 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 1929 process->pid,
1930 process->ppid,
1931 g_quark_to_string(process->name),
1932 g_quark_to_string(process->brand),
1933 g_quark_to_string(process->state->s));
3d27549e 1934 return;
1935 }
b445142a 1936
f95bc830 1937 if(depth == 1){
00e74b69 1938 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 1939 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1940 return;
1941 }
1942
e05fc742 1943 process->execution_stack =
1944 g_array_set_size(process->execution_stack, depth - 1);
b445142a 1945 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 1946 depth - 2);
b445142a 1947 process->state->change = tfs->parent.timestamp;
dc877563 1948}
1949
6806b3c6 1950struct search_result {
80e0221b 1951 const LttTime *time; /* Requested time */
1952 LttTime *best; /* Best result */
6806b3c6 1953};
1954
1955static gint search_usertrace(gconstpointer a, gconstpointer b)
1956{
80e0221b 1957 const LttTime *elem_time = (const LttTime*)a;
1958 /* Explicit non const cast */
1959 struct search_result *res = (struct search_result *)b;
1960
1961 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1962 /* The usertrace was created before the schedchange */
1963 /* Get larger keys */
1964 return 1;
1965 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1966 /* The usertrace was created after the schedchange time */
1967 /* Get smaller keys */
1968 if(res->best) {
1969 if(ltt_time_compare(*elem_time, *res->best) < 0) {
e1de4b54 1970 res->best = (LttTime *)elem_time;
80e0221b 1971 }
1972 } else {
e1de4b54 1973 res->best = (LttTime *)elem_time;
80e0221b 1974 }
1975 return -1;
1976 }
1977 return 0;
6806b3c6 1978}
1979
1980static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
80e0221b 1981 guint pid, const LttTime *timestamp)
1982{
1983 LttvTracefileState *tfs = NULL;
1984 struct search_result res;
1985 /* Find the usertrace associated with a pid and time interval.
1986 * Search in the usertraces by PID (within a hash) and then, for each
1987 * corresponding element of the array, find the first one with creation
1988 * timestamp the lowest, but higher or equal to "timestamp". */
1989 res.time = timestamp;
1990 res.best = NULL;
1991 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1992 if(usertrace_tree) {
1993 g_tree_search(usertrace_tree, search_usertrace, &res);
1994 if(res.best)
1995 tfs = g_tree_lookup(usertrace_tree, res.best);
1996 }
6806b3c6 1997
80e0221b 1998 return tfs;
6806b3c6 1999}
2000
dc877563 2001
2a2fa4f0 2002LttvProcessState *
348c6ba8 2003lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
fcc08e1e 2004 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
dc877563 2005{
2006 LttvProcessState *process = g_new(LttvProcessState, 1);
2007
b445142a 2008 LttvExecutionState *es;
dc877563 2009
b445142a 2010 char buffer[128];
ffd54a90 2011
dc877563 2012 process->pid = pid;
fcc08e1e 2013 process->tgid = tgid;
348c6ba8 2014 process->cpu = cpu;
b3fd4c02 2015 process->name = name;
7b5f6cf1 2016 process->brand = LTTV_STATE_UNBRANDED;
348c6ba8 2017 //process->last_cpu = tfs->cpu_name;
2018 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
80e0221b 2019 process->type = LTTV_STATE_USER_THREAD;
2020 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2021 process->current_function = 0; //function 0x0 by default.
7bfd7820 2022
cb03932a 2023 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 2024 g_hash_table_insert(tcs->processes, process, process);
b445142a 2025
2026 if(parent) {
2027 process->ppid = parent->pid;
348c6ba8 2028 process->creation_time = *timestamp;
b445142a 2029 }
2a2fa4f0 2030
2031 /* No parent. This process exists but we are missing all information about
2032 its creation. The birth time is set to zero but we remember the time of
2033 insertion */
2034
b445142a 2035 else {
2036 process->ppid = 0;
2a2fa4f0 2037 process->creation_time = ltt_time_zero;
b445142a 2038 }
2039
348c6ba8 2040 process->insertion_time = *timestamp;
b445142a 2041 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
80e0221b 2042 process->creation_time.tv_nsec);
b445142a 2043 process->pid_time = g_quark_from_string(buffer);
348c6ba8 2044 process->cpu = cpu;
2045 //process->last_cpu = tfs->cpu_name;
2046 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 2047 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2048 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
c607371b 2049 process->execution_stack = g_array_set_size(process->execution_stack, 2);
b445142a 2050 es = process->state = &g_array_index(process->execution_stack,
2051 LttvExecutionState, 0);
2052 es->t = LTTV_STATE_USER_MODE;
2053 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 2054 es->entry = *timestamp;
2055 //g_assert(timestamp->tv_sec != 0);
2056 es->change = *timestamp;
80e0221b 2057 es->cum_cpu_time = ltt_time_zero;
c607371b 2058 es->s = LTTV_STATE_RUN;
2059
2060 es = process->state = &g_array_index(process->execution_stack,
2061 LttvExecutionState, 1);
2062 es->t = LTTV_STATE_SYSCALL;
2063 es->n = LTTV_STATE_SUBMODE_NONE;
2064 es->entry = *timestamp;
2065 //g_assert(timestamp->tv_sec != 0);
2066 es->change = *timestamp;
80e0221b 2067 es->cum_cpu_time = ltt_time_zero;
c3b3b60b 2068 es->s = LTTV_STATE_WAIT_FORK;
80e0221b 2069
2070 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2071 process->user_stack = g_array_sized_new(FALSE, FALSE,
2072 sizeof(guint64), 0);
2073
cbe7c836 2074 return process;
dc877563 2075}
2076
348c6ba8 2077LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 2078 guint pid)
dc877563 2079{
2a2fa4f0 2080 LttvProcessState key;
2081 LttvProcessState *process;
2082
2083 key.pid = pid;
348c6ba8 2084 key.cpu = cpu;
2a2fa4f0 2085 process = g_hash_table_lookup(ts->processes, &key);
dc877563 2086 return process;
2087}
2088
2a2fa4f0 2089LttvProcessState *
348c6ba8 2090lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
d41c66bf 2091 const LttTime *timestamp)
2a2fa4f0 2092{
348c6ba8 2093 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
7bfd7820 2094 LttvExecutionState *es;
348c6ba8 2095
2096 /* Put ltt_time_zero creation time for unexisting processes */
7bfd7820 2097 if(unlikely(process == NULL)) {
80e0221b 2098 process = lttv_state_create_process(ts,
fcc08e1e 2099 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
80e0221b 2100 /* We are not sure is it's a kernel thread or normal thread, put the
2101 * bottom stack state to unknown */
c3b3b60b 2102 process->execution_stack =
2103 g_array_set_size(process->execution_stack, 1);
2104 process->state = es =
2105 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2106 es->t = LTTV_STATE_MODE_UNKNOWN;
c4a72569 2107 es->s = LTTV_STATE_UNNAMED;
80e0221b 2108 }
2a2fa4f0 2109 return process;
2110}
2111
41c7f803 2112/* FIXME : this function should be called when we receive an event telling that
2113 * release_task has been called in the kernel. In happens generally when
2114 * the parent waits for its child terminaison, but may also happen in special
2115 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2116 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2117 * of a killed thread ground, but isn't the leader.
41c7f803 2118 */
b445142a 2119static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 2120{
ba576a78 2121 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 2122 LttvProcessState key;
ba576a78 2123
2a2fa4f0 2124 key.pid = process->pid;
348c6ba8 2125 key.cpu = process->cpu;
2a2fa4f0 2126 g_hash_table_remove(ts->processes, &key);
b445142a 2127 g_array_free(process->execution_stack, TRUE);
302efbad 2128 g_array_free(process->user_stack, TRUE);
dc877563 2129 g_free(process);
2130}
2131
2132
b445142a 2133static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 2134{
b445142a 2135 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
302efbad 2136 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
dc877563 2137 g_free(value);
2138}
2139
2140
308711e5 2141static void lttv_state_free_process_table(GHashTable *processes)
dc877563 2142{
2143 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 2144 g_hash_table_destroy(processes);
dc877563 2145}
2146
2147
b445142a 2148static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 2149{
ba576a78 2150 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2151 guint cpu = s->cpu;
2152 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2153 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 2154 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2155 LttvTraceHook *th = (LttvTraceHook *)hook_data;
775c802c 2156 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2157
b445142a 2158 LttvExecutionSubmode submode;
2159
80e0221b 2160 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2161 guint syscall = ltt_event_get_unsigned(e, f);
2162
2163 if(syscall < nb_syscalls) {
2164 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2165 syscall];
2166 } else {
2167 /* Fixup an incomplete syscall table */
2168 GString *string = g_string_new("");
7cd289b0 2169 g_string_printf(string, "syscall %u", syscall);
80e0221b 2170 submode = g_quark_from_string(string->str);
2171 g_string_free(string, TRUE);
2172 }
1e304fa1 2173 /* There can be no system call from PID 0 : unknown state */
2174 if(process->pid != 0)
2175 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 2176 return FALSE;
2177}
2178
2179
b445142a 2180static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 2181{
ba576a78 2182 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2183 guint cpu = s->cpu;
2184 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2185 LttvProcessState *process = ts->running_process[cpu];
dc877563 2186
1e304fa1 2187 /* There can be no system call from PID 0 : unknown state */
2188 if(process->pid != 0)
2189 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 2190 return FALSE;
2191}
2192
2193
b445142a 2194static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 2195{
ba576a78 2196 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 2197 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2198 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2199 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2200
b445142a 2201 LttvExecutionSubmode submode;
2202
17ddd1f2 2203 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2204 guint64 trap = ltt_event_get_long_unsigned(e, f);
5e96e7e3 2205
2206 if(trap < nb_traps) {
2207 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2208 } else {
2209 /* Fixup an incomplete trap table */
2210 GString *string = g_string_new("");
fcc08e1e 2211 g_string_printf(string, "trap %llu", trap);
5e96e7e3 2212 submode = g_quark_from_string(string->str);
2213 g_string_free(string, TRUE);
2214 }
2215
b445142a 2216 push_state(s, LTTV_STATE_TRAP, submode);
d3d99fde 2217
2218 /* update cpu status */
2219 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2220
dc877563 2221 return FALSE;
2222}
2223
b445142a 2224static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 2225{
ba576a78 2226 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 2227
ffd54a90 2228 pop_state(s, LTTV_STATE_TRAP);
d3d99fde 2229
2230 /* update cpu status */
2231 cpu_pop_mode(s->cpu_state);
2232
dc877563 2233 return FALSE;
2234}
2235
b445142a 2236static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 2237{
ba576a78 2238 LttvTracefileState *s = (LttvTracefileState *)call_data;
5e563da0 2239 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
eed2ef37 2240 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2241 //guint8 ev_id = ltt_event_eventtype_id(e);
2242 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2243 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2244
b445142a 2245 LttvExecutionSubmode submode;
1bb8d3a5 2246 guint64 irq = ltt_event_get_long_unsigned(e, f);
6214c229 2247 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
b445142a 2248
6214c229 2249 if(irq < nb_irqs) {
2250 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2251 } else {
2252 /* Fixup an incomplete irq table */
2253 GString *string = g_string_new("");
2254 g_string_printf(string, "irq %llu", irq);
2255 submode = g_quark_from_string(string->str);
2256 g_string_free(string, TRUE);
2257 }
b445142a 2258
dc877563 2259 /* Do something with the info about being in user or system mode when int? */
b445142a 2260 push_state(s, LTTV_STATE_IRQ, submode);
598026ba 2261
2262 /* update cpu status */
d3d99fde 2263 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
598026ba 2264
5e563da0 2265 /* update irq status */
8743690d 2266 s->cpu_state->last_irq = irq;
5e563da0 2267 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2268
dc877563 2269 return FALSE;
2270}
2271
302efbad 2272static gboolean soft_irq_exit(void *hook_data, void *call_data)
2273{
2274 LttvTracefileState *s = (LttvTracefileState *)call_data;
2275
2276 pop_state(s, LTTV_STATE_SOFT_IRQ);
2277 return FALSE;
2278}
2279
2280
dc877563 2281
b445142a 2282static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 2283{
ba576a78 2284 LttvTracefileState *s = (LttvTracefileState *)call_data;
8743690d 2285 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
dc877563 2286
ffd54a90 2287 pop_state(s, LTTV_STATE_IRQ);
598026ba 2288
2289 /* update cpu status */
d3d99fde 2290 cpu_pop_mode(s->cpu_state);
598026ba 2291
8743690d 2292 /* update irq status */
2293 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2294
dc877563 2295 return FALSE;
2296}
2297
faf074a3 2298static gboolean soft_irq_entry(void *hook_data, void *call_data)
2299{
2300 LttvTracefileState *s = (LttvTracefileState *)call_data;
2301 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2302 //guint8 ev_id = ltt_event_eventtype_id(e);
2303 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2304 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
faf074a3 2305
2306 LttvExecutionSubmode submode;
1bb8d3a5 2307 guint64 softirq = ltt_event_get_long_unsigned(e, f);
6214c229 2308 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
faf074a3 2309
6214c229 2310 if(softirq < nb_softirqs) {
2311 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2312 } else {
2313 /* Fixup an incomplete irq table */
2314 GString *string = g_string_new("");
2315 g_string_printf(string, "softirq %llu", softirq);
2316 submode = g_quark_from_string(string->str);
2317 g_string_free(string, TRUE);
2318 }
faf074a3 2319
2320 /* Do something with the info about being in user or system mode when int? */
2321 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2322 return FALSE;
2323}
2324
38b73700 2325static gboolean enum_interrupt(void *hook_data, void *call_data)
2326{
2327 LttvTracefileState *s = (LttvTracefileState *)call_data;
2328 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2329 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2330 //guint8 ev_id = ltt_event_eventtype_id(e);
2331 LttvTraceHook *th = (LttvTraceHook *)hook_data;
38b73700 2332
d3a66443 2333 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2334 lttv_trace_get_hook_field(th, 0)));
2335 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
38b73700 2336
2337 ts->irq_names[irq] = action;
2338
2339 return FALSE;
2340}
2341
2342
27811799 2343static gboolean bdev_request_issue(void *hook_data, void *call_data)
2344{
2345 LttvTracefileState *s = (LttvTracefileState *)call_data;
2346 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2347 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2348 //guint8 ev_id = ltt_event_eventtype_id(e);
2349 LttvTraceHook *th = (LttvTraceHook *)hook_data;
27811799 2350
d3a66443 2351 guint major = ltt_event_get_long_unsigned(e,
2352 lttv_trace_get_hook_field(th, 0));
2353 guint minor = ltt_event_get_long_unsigned(e,
2354 lttv_trace_get_hook_field(th, 1));
2355 guint oper = ltt_event_get_long_unsigned(e,
2356 lttv_trace_get_hook_field(th, 2));
27811799 2357 guint16 devcode = MKDEV(major,minor);
2358
2359 /* have we seen this block device before? */
98d7814f 2360 gpointer bdev = get_hashed_bdevstate(ts, devcode);
27811799 2361
2362 if(oper == 0)
2363 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2364 else
2365 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2366
2367 return FALSE;
2368}
2369
2370static gboolean bdev_request_complete(void *hook_data, void *call_data)
2371{
2372 LttvTracefileState *s = (LttvTracefileState *)call_data;
2373 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2374 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2375 LttvTraceHook *th = (LttvTraceHook *)hook_data;
27811799 2376
d3a66443 2377 guint major = ltt_event_get_long_unsigned(e,
2378 lttv_trace_get_hook_field(th, 0));
2379 guint minor = ltt_event_get_long_unsigned(e,
2380 lttv_trace_get_hook_field(th, 1));
2381 //guint oper = ltt_event_get_long_unsigned(e,
2382 // lttv_trace_get_hook_field(th, 2));
27811799 2383 guint16 devcode = MKDEV(major,minor);
2384
2385 /* have we seen this block device before? */
98d7814f 2386 gpointer bdev = get_hashed_bdevstate(ts, devcode);
27811799 2387
2388 /* update block device */
2389 bdev_pop_mode(bdev);
2390
2391 return FALSE;
2392}
2393
302efbad 2394static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2395{
2396 guint64 *new_func;
2397
2398 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2399 guint cpu = tfs->cpu;
2400 LttvProcessState *process = ts->running_process[cpu];
faf074a3 2401
302efbad 2402 guint depth = process->user_stack->len;
2403
d3a66443 2404 process->user_stack =
302efbad 2405 g_array_set_size(process->user_stack, depth + 1);
2406
2407 new_func = &g_array_index(process->user_stack, guint64, depth);
80e0221b 2408 *new_func = funcptr;
9bff13df 2409 process->current_function = funcptr;
302efbad 2410}
2411
2412static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2413{
2414 guint cpu = tfs->cpu;
2415 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2416 LttvProcessState *process = ts->running_process[cpu];
2417
302efbad 2418 if(process->current_function != funcptr){
2419 g_info("Different functions (%lu.%09lu): ignore it\n",
2420 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2421 g_info("process state has %llu when pop_function is %llu\n",
80e0221b 2422 process->current_function, funcptr);
7b5f6cf1 2423 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 2424 process->pid,
2425 process->ppid,
2426 g_quark_to_string(process->name),
2427 g_quark_to_string(process->brand),
2428 g_quark_to_string(process->state->s));
302efbad 2429 return;
2430 }
9bff13df 2431 guint depth = process->user_stack->len;
302efbad 2432
2433 if(depth == 0){
2434 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2435 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2436 return;
2437 }
2438
2439 process->user_stack =
2440 g_array_set_size(process->user_stack, depth - 1);
2441 process->current_function =
80e0221b 2442 g_array_index(process->user_stack, guint64, depth - 2);
302efbad 2443}
2444
2445
2446static gboolean function_entry(void *hook_data, void *call_data)
faf074a3 2447{
2448 LttvTracefileState *s = (LttvTracefileState *)call_data;
302efbad 2449 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2450 //guint8 ev_id = ltt_event_eventtype_id(e);
2451 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2452 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
80e0221b 2453 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
faf074a3 2454
302efbad 2455 push_function(s, funcptr);
faf074a3 2456 return FALSE;
2457}
2458
302efbad 2459static gboolean function_exit(void *hook_data, void *call_data)
2460{
2461 LttvTracefileState *s = (LttvTracefileState *)call_data;
2462 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2463 //guint8 ev_id = ltt_event_eventtype_id(e);
2464 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2465 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
80e0221b 2466 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
302efbad 2467
302efbad 2468 pop_function(s, funcptr);
2469 return FALSE;
2470}
dc877563 2471
b445142a 2472static gboolean schedchange(void *hook_data, void *call_data)
dc877563 2473{
ba576a78 2474 LttvTracefileState *s = (LttvTracefileState *)call_data;
ae3d0f50 2475 guint cpu = s->cpu;
348c6ba8 2476 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2477 LttvProcessState *process = ts->running_process[cpu];
5fd4c7a2 2478 //LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 2479
eed2ef37 2480 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2481 LttvTraceHook *th = (LttvTraceHook *)hook_data;
73394fd3 2482 guint pid_in, pid_out;
7092fb86 2483 gint64 state_out;
dc877563 2484
d3a66443 2485 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2486 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2487 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
348c6ba8 2488
2489 if(likely(process != NULL)) {
b445142a 2490
f95bc830 2491 /* We could not know but it was not the idle process executing.
2492 This should only happen at the beginning, before the first schedule
2493 event, and when the initial information (current process for each CPU)
2494 is missing. It is not obvious how we could, after the fact, compensate
2495 the wrongly attributed statistics. */
2496
240f1fea 2497 //This test only makes sense once the state is known and if there is no
48b002b8 2498 //missing events. We need to silently ignore schedchange coming after a
80e0221b 2499 //process_free, or it causes glitches. (FIXME)
348c6ba8 2500 //if(unlikely(process->pid != pid_out)) {
2501 // g_assert(process->pid == 0);
240f1fea 2502 //}
c4a72569 2503 if(process->pid == 0
2504 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2505 if(pid_out == 0) {
2506 /* Scheduling out of pid 0 at beginning of the trace :
2507 * we know for sure it is in syscall mode at this point. */
2508 g_assert(process->execution_stack->len == 1);
2509 process->state->t = LTTV_STATE_SYSCALL;
2510 process->state->s = LTTV_STATE_WAIT;
2511 process->state->change = s->parent.timestamp;
d3670e3d 2512 process->state->entry = s->parent.timestamp;
c4a72569 2513 }
dbd243b1 2514 } else {
c4a72569 2515 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2516 process->state->s = LTTV_STATE_ZOMBIE;
2517 process->state->change = s->parent.timestamp;
2518 } else {
2519 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2520 else process->state->s = LTTV_STATE_WAIT;
2521 process->state->change = s->parent.timestamp;
2522 }
2523
5fe0b9ca 2524 if(state_out == 32 || state_out == 128)
2525 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
c4a72569 2526 /* see sched.h for states */
791dffa6 2527 }
dc877563 2528 }
348c6ba8 2529 process = ts->running_process[cpu] =
2530 lttv_state_find_process_or_create(
2531 (LttvTraceState*)s->parent.t_context,
2532 cpu, pid_in,
2533 &s->parent.timestamp);
2534 process->state->s = LTTV_STATE_RUN;
2535 process->cpu = cpu;
80e0221b 2536 if(process->usertrace)
2537 process->usertrace->cpu = cpu;
348c6ba8 2538 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2539 process->state->change = s->parent.timestamp;
44ffb95f 2540
2541 /* update cpu status */
2542 if(pid_in == 0)
d3d99fde 2543 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
44ffb95f 2544 else
d3d99fde 2545 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
44ffb95f 2546
dc877563 2547 return FALSE;
2548}
2549
eed2ef37 2550static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2551{
eed2ef37 2552 LttvTracefileState *s = (LttvTracefileState *)call_data;
2553 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2554 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2555 guint parent_pid;
fcc08e1e 2556 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2557 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
0ceef9de 2558 //LttvProcessState *zombie_process;
ae3d0f50 2559 guint cpu = s->cpu;
348c6ba8 2560 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2561 LttvProcessState *process = ts->running_process[cpu];
26275aa2 2562 LttvProcessState *child_process;
d3a66443 2563 struct marker_field *f;
2cdc690b 2564
eed2ef37 2565 /* Parent PID */
d3a66443 2566 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
eed2ef37 2567
2cdc690b 2568 /* Child PID */
d3a66443 2569 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
33bdc8dd 2570 s->parent.target_pid = child_pid;
2cdc690b 2571
fcc08e1e 2572 /* Child TGID */
d3a66443 2573 f = lttv_trace_get_hook_field(th, 2);
2574 if (likely(f))
2575 child_tgid = ltt_event_get_unsigned(e, f);
2576 else
2577 child_tgid = 0;
fcc08e1e 2578
15b3d537 2579 /* Mathieu : it seems like the process might have been scheduled in before the
2580 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 2581 * in a SMP case where we don't have enough precision on the clocks.
2582 *
2583 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2584#if 0
348c6ba8 2585 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 2586
1d1df11d 2587 if(unlikely(zombie_process != NULL)) {
4ad73431 2588 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 2589 * has been released. FIXME : should know when release_task happens instead.
4ad73431 2590 */
15b3d537 2591 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2592 guint i;
2593 for(i=0; i< num_cpus; i++) {
5ac05980 2594 g_assert(zombie_process != ts->running_process[i]);
15b3d537 2595 }
2596
4ad73431 2597 exit_process(s, zombie_process);
2598 }
791dffa6 2599#endif //0
348c6ba8 2600 g_assert(process->pid != child_pid);
eed2ef37 2601 // FIXME : Add this test in the "known state" section
348c6ba8 2602 // g_assert(process->pid == parent_pid);
26275aa2 2603 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2604 if(child_process == NULL) {
ab893fb1 2605 child_process = lttv_state_create_process(ts, process, cpu,
fcc08e1e 2606 child_pid, child_tgid,
2607 LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 2608 } else {
2609 /* The process has already been created : due to time imprecision between
791dffa6 2610 * multiple CPUs : it has been scheduled in before creation. Note that we
2611 * shouldn't have this kind of imprecision.
26275aa2 2612 *
2613 * Simply put a correct parent.
2614 */
6806b3c6 2615 g_assert(0); /* This is a problematic case : the process has been created
2616 before the fork event */
26275aa2 2617 child_process->ppid = process->pid;
fcc08e1e 2618 child_process->tgid = child_tgid;
26275aa2 2619 }
0292757b 2620 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2621 child_process->name = process->name;
2622 child_process->brand = process->brand;
4ad73431 2623
dc877563 2624 return FALSE;
2625}
2626
89f8741a 2627/* We stamp a newly created process as kernel_thread.
2628 * The thread should not be running yet. */
7bfd7820 2629static gboolean process_kernel_thread(void *hook_data, void *call_data)
2630{
2631 LttvTracefileState *s = (LttvTracefileState *)call_data;
2632 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2633 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7bfd7820 2634 guint pid;
7bfd7820 2635 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2636 LttvProcessState *process;
2637 LttvExecutionState *es;
2638
2639 /* PID */
d3a66443 2640 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2641 s->parent.target_pid = pid;
7bfd7820 2642
61c8808e 2643 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2644 &ltt_time_zero);
15f3a340 2645 process->execution_stack =
2646 g_array_set_size(process->execution_stack, 1);
2647 es = process->state =
2648 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2649 es->t = LTTV_STATE_SYSCALL;
2650 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 2651
80e0221b 2652 return FALSE;
7bfd7820 2653}
dc877563 2654
eed2ef37 2655static gboolean process_exit(void *hook_data, void *call_data)
dc877563 2656{
eed2ef37 2657 LttvTracefileState *s = (LttvTracefileState *)call_data;
2658 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2659 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2660 guint pid;
348c6ba8 2661 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
6f54e0f4 2662 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 2663
d3a66443 2664 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2665 s->parent.target_pid = pid;
eed2ef37 2666
2667 // FIXME : Add this test in the "known state" section
348c6ba8 2668 // g_assert(process->pid == pid);
eed2ef37 2669
6f54e0f4 2670 process = lttv_state_find_process(ts, ANY_CPU, pid);
348c6ba8 2671 if(likely(process != NULL)) {
2672 process->state->s = LTTV_STATE_EXIT;
2cdc690b 2673 }
2674 return FALSE;
2cdc690b 2675}
2676
eed2ef37 2677static gboolean process_free(void *hook_data, void *call_data)
2da61677 2678{
eed2ef37 2679 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 2680 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 2681 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2682 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2da61677 2683 guint release_pid;
2684 LttvProcessState *process;
2685
2686 /* PID of the process to release */
d3a66443 2687 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2688 s->parent.target_pid = release_pid;
15b3d537 2689
2690 g_assert(release_pid != 0);
2da61677 2691
348c6ba8 2692 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 2693
2694 if(likely(process != NULL)) {
2695 /* release_task is happening at kernel level : we can now safely release
2696 * the data structure of the process */
5562ddce 2697 //This test is fun, though, as it may happen that
2698 //at time t : CPU 0 : process_free
2699 //at time t+150ns : CPU 1 : schedule out
2700 //Clearly due to time imprecision, we disable it. (Mathieu)
2701 //If this weird case happen, we have no choice but to put the
2702 //Currently running process on the cpu to 0.
791dffa6 2703 //I re-enable it following time precision fixes. (Mathieu)
2704 //Well, in the case where an process is freed by a process on another CPU
2705 //and still scheduled, it happens that this is the schedchange that will
2706 //drop the last reference count. Do not free it here!
0bd2f89c 2707 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2708 guint i;
2709 for(i=0; i< num_cpus; i++) {
5562ddce 2710 //g_assert(process != ts->running_process[i]);
2711 if(process == ts->running_process[i]) {
791dffa6 2712 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2713 break;
5562ddce 2714 }
0bd2f89c 2715 }
6f54e0f4 2716 if(i == num_cpus) /* process is not scheduled */
2717 exit_process(s, process);
2da61677 2718 }
2719
2720 return FALSE;
2721}
2722
f4b88a7d 2723
2724static gboolean process_exec(void *hook_data, void *call_data)
2725{
2726 LttvTracefileState *s = (LttvTracefileState *)call_data;
2727 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2728 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2729 LttvTraceHook *th = (LttvTraceHook *)hook_data;
743e50fd 2730 //gchar *name;
ae3d0f50 2731 guint cpu = s->cpu;
f4b88a7d 2732 LttvProcessState *process = ts->running_process[cpu];
2733
f63ebe51 2734#if 0//how to use a sequence that must be transformed in a string
f4b88a7d 2735 /* PID of the process to release */
d3a66443 2736 guint64 name_len = ltt_event_field_element_number(e,
2737 lttv_trace_get_hook_field(th, 0));
2738 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2739 LttField *child = ltt_event_field_element_select(e,
2740 lttv_trace_get_hook_field(th, 0), 0);
f2923fb2 2741 gchar *name_begin =
2742 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 2743 gchar *null_term_name = g_new(gchar, name_len+1);
2744 memcpy(null_term_name, name_begin, name_len);
2745 null_term_name[name_len] = '\0';
743e50fd 2746 process->name = g_quark_from_string(null_term_name);
f63ebe51 2747#endif //0
2748
d3a66443 2749 process->name = g_quark_from_string(ltt_event_get_string(e,
2750 lttv_trace_get_hook_field(th, 0)));
0292757b 2751 process->brand = LTTV_STATE_UNBRANDED;
f63ebe51 2752 //g_free(null_term_name);
f4b88a7d 2753 return FALSE;
2754}
2755
7b5f6cf1 2756static gboolean thread_brand(void *hook_data, void *call_data)
2757{
2758 LttvTracefileState *s = (LttvTracefileState *)call_data;
2759 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2760 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2761 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7b5f6cf1 2762 gchar *name;
2763 guint cpu = s->cpu;
2764 LttvProcessState *process = ts->running_process[cpu];
2765
d3a66443 2766 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
7b5f6cf1 2767 process->brand = g_quark_from_string(name);
2768
2769 return FALSE;
2770}
2771
c3b3b60b 2772static void fix_process(gpointer key, gpointer value,
2773 gpointer user_data)
2774{
2775 LttvProcessState *process;
2776 LttvExecutionState *es;
2777 process = (LttvProcessState *)value;
c3b3b60b 2778 LttTime *timestamp = (LttTime*)user_data;
2779
c3b3b60b 2780 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2b25224d 2781 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2782 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2783 es->t = LTTV_STATE_SYSCALL;
2b25224d 2784 es->n = LTTV_STATE_SUBMODE_NONE;
2785 es->entry = *timestamp;
2786 es->change = *timestamp;
2787 es->cum_cpu_time = ltt_time_zero;
c4a72569 2788 if(es->s == LTTV_STATE_UNNAMED)
2789 es->s = LTTV_STATE_WAIT;
c3b3b60b 2790 }
2791 } else {
2b25224d 2792 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2793 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
c3b3b60b 2794 es->t = LTTV_STATE_USER_MODE;
2795 es->n = LTTV_STATE_SUBMODE_NONE;
2796 es->entry = *timestamp;
2797 //g_assert(timestamp->tv_sec != 0);
2798 es->change = *timestamp;
2799 es->cum_cpu_time = ltt_time_zero;
c4a72569 2800 if(es->s == LTTV_STATE_UNNAMED)
2801 es->s = LTTV_STATE_RUN;
c3b3b60b 2802
2b25224d 2803 if(process->execution_stack->len == 1) {
89f8741a 2804 /* Still in bottom unknown mode, means never did a system call
2805 * May be either in user mode, syscall mode, running or waiting.*/
2806 /* FIXME : we may be tagging syscall mode when being user mode */
2b25224d 2807 process->execution_stack =
2808 g_array_set_size(process->execution_stack, 2);
2809 es = process->state = &g_array_index(process->execution_stack,
c3b3b60b 2810 LttvExecutionState, 1);
2b25224d 2811 es->t = LTTV_STATE_SYSCALL;
2812 es->n = LTTV_STATE_SUBMODE_NONE;
2813 es->entry = *timestamp;
2814 //g_assert(timestamp->tv_sec != 0);
2815 es->change = *timestamp;
2816 es->cum_cpu_time = ltt_time_zero;
b59b7222 2817 if(es->s == LTTV_STATE_WAIT_FORK)
2818 es->s = LTTV_STATE_WAIT;
2b25224d 2819 }
c3b3b60b 2820 }
2821 }
2822}
2823
2824static gboolean statedump_end(void *hook_data, void *call_data)
2825{
2826 LttvTracefileState *s = (LttvTracefileState *)call_data;
2827 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2828 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
0ceef9de 2829 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2830 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
c3b3b60b 2831
2832 /* For all processes */
2833 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2834 /* else, if stack[0] is unknown, set to user mode, running */
2835
2836 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
0ceef9de 2837
2838 return FALSE;
c3b3b60b 2839}
2840
b3fd4c02 2841static gboolean enum_process_state(void *hook_data, void *call_data)
2842{
2843 LttvTracefileState *s = (LttvTracefileState *)call_data;
2844 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
80e0221b 2845 //It's slow : optimise later by doing this before reading trace.
0ceef9de 2846 LttvTraceHook *th = (LttvTraceHook *)hook_data;
b3fd4c02 2847 guint parent_pid;
2848 guint pid;
fcc08e1e 2849 guint tgid;
b3fd4c02 2850 gchar * command;
ae3d0f50 2851 guint cpu = s->cpu;
b3fd4c02 2852 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2853 LttvProcessState *process = ts->running_process[cpu];
2854 LttvProcessState *parent_process;
d3a66443 2855 struct marker_field *f;
80e0221b 2856 GQuark type, mode, submode, status;
2857 LttvExecutionState *es;
c4a72569 2858 guint i, nb_cpus;
f4b88a7d 2859
b3fd4c02 2860 /* PID */
d3a66443 2861 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
e38d9ea0 2862 s->parent.target_pid = pid;
2863
b3fd4c02 2864 /* Parent PID */
d3a66443 2865 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
b3fd4c02 2866
2867 /* Command name */
d3a66443 2868 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
b3fd4c02 2869
80e0221b 2870 /* type */
d3a66443 2871 f = lttv_trace_get_hook_field(th, 3);
deb8b4b2 2872 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 2873
80e0221b 2874 /* mode */
d3a66443 2875 f = lttv_trace_get_hook_field(th, 4);
deb8b4b2 2876 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
b3fd4c02 2877
80e0221b 2878 /* submode */
d3a66443 2879 f = lttv_trace_get_hook_field(th, 5);
deb8b4b2 2880 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 2881
80e0221b 2882 /* status */
d3a66443 2883 f = lttv_trace_get_hook_field(th, 6);
deb8b4b2 2884 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
e62e7f3a 2885
fcc08e1e 2886 /* TGID */
d3a66443 2887 f = lttv_trace_get_hook_field(th, 7);
2888 if(f)
2889 tgid = ltt_event_get_unsigned(e, f);
2890 else
2891 tgid = 0;
c4a72569 2892
2893 if(pid == 0) {
2894 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2895 for(i=0; i<nb_cpus; i++) {
2896 process = lttv_state_find_process(ts, i, pid);
2897 g_assert(process != NULL);
2898
2899 process->ppid = parent_pid;
2900 process->tgid = tgid;
2901 process->name = g_quark_from_string(command);
2902 es =
2903 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2904 process->type = LTTV_STATE_KERNEL_THREAD;
c4a72569 2905 }
2906
2907 } else {
2908 /* The process might exist if a process was forked while performing the
2909 * state dump. */
2910 process = lttv_state_find_process(ts, ANY_CPU, pid);
2911 if(process == NULL) {
2912 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2913 process = lttv_state_create_process(ts, parent_process, cpu,
2914 pid, tgid, g_quark_from_string(command),
2915 &s->parent.timestamp);
2916
2917 /* Keep the stack bottom : a running user mode */
2918 /* Disabled because of inconsistencies in the current statedump states. */
2919 if(type == LTTV_STATE_KERNEL_THREAD) {
2920 /* Only keep the bottom
2921 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2922 /* Will cause expected trap when in fact being syscall (even after end of
2923 * statedump event)
2924 * Will cause expected interrupt when being syscall. (only before end of
2925 * statedump event) */
2926 // This will cause a "popping last state on stack, ignoring it."
2927 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2928 es = process->state = &g_array_index(process->execution_stack,
2929 LttvExecutionState, 0);
2930 process->type = LTTV_STATE_KERNEL_THREAD;
2931 es->t = LTTV_STATE_MODE_UNKNOWN;
2932 es->s = LTTV_STATE_UNNAMED;
2933 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2934 #if 0
2935 es->t = LTTV_STATE_SYSCALL;
2936 es->s = status;
2937 es->n = submode;
2938 #endif //0
2939 } else {
2940 /* User space process :
2941 * bottom : user mode
2942 * either currently running or scheduled out.
2943 * can be scheduled out because interrupted in (user mode or in syscall)
2944 * or because of an explicit call to the scheduler in syscall. Note that
2945 * the scheduler call comes after the irq_exit, so never in interrupt
2946 * context. */
2947 // temp workaround : set size to 1 : only have user mode bottom of stack.
2948 // will cause g_info message of expected syscall mode when in fact being
2949 // in user mode. Can also cause expected trap when in fact being user
2950 // mode in the event of a page fault reenabling interrupts in the handler.
2951 // Expected syscall and trap can also happen after the end of statedump
2952 // This will cause a "popping last state on stack, ignoring it."
2953 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2954 es = process->state = &g_array_index(process->execution_stack,
2955 LttvExecutionState, 0);
2956 es->t = LTTV_STATE_MODE_UNKNOWN;
2957 es->s = LTTV_STATE_UNNAMED;
2958 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2959 #if 0
2960 es->t = LTTV_STATE_USER_MODE;
2961 es->s = status;
2962 es->n = submode;
2963 #endif //0
2964 }
2965 #if 0
2966 /* UNKNOWN STATE */
2967 {
2968 es = process->state = &g_array_index(process->execution_stack,
2969 LttvExecutionState, 1);
2970 es->t = LTTV_STATE_MODE_UNKNOWN;
2971 es->s = LTTV_STATE_UNNAMED;
2972 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2973 }
2974 #endif //0
80e0221b 2975 } else {
c4a72569 2976 /* The process has already been created :
2977 * Probably was forked while dumping the process state or
2978 * was simply scheduled in prior to get the state dump event.
2979 */
2980 process->ppid = parent_pid;
2981 process->tgid = tgid;
2982 process->name = g_quark_from_string(command);
2983 process->type = type;
2984 es =
2985 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2986#if 0
c4a72569 2987 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2988 if(type == LTTV_STATE_KERNEL_THREAD)
2989 es->t = LTTV_STATE_SYSCALL;
2990 else
2991 es->t = LTTV_STATE_USER_MODE;
2992 }
cab321cf 2993#endif //0
c4a72569 2994 /* Don't mess around with the stack, it will eventually become
2995 * ok after the end of state dump. */
80e0221b 2996 }
b3fd4c02 2997 }
2998
2999 return FALSE;
3000}
f4b88a7d 3001
58c88a41 3002gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3003{
3004 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3005
3006 lttv_state_add_event_hooks(tss);
3007
3008 return 0;
3009}
dc877563 3010
308711e5 3011void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 3012{
ba576a78 3013 LttvTraceset *traceset = self->parent.ts;
dc877563 3014
8979f265 3015 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3016
ba576a78 3017 LttvTraceState *ts;
dc877563 3018
ba576a78 3019 LttvTracefileState *tfs;
dc877563 3020
dc877563 3021 GArray *hooks;
3022
0ceef9de 3023 LttvTraceHook *th;
eed2ef37 3024
dc877563 3025 LttvAttributeValue val;
3026
ba576a78 3027 nb_trace = lttv_traceset_number(traceset);
dc877563 3028 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 3029 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 3030
3031 /* Find the eventtype id for the following events and register the
3032 associated by id hooks. */
3033
c3b3b60b 3034 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
6418800d 3035 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3036 //hn = 0;
b445142a 3037
6418800d 3038 lttv_trace_find_hook(ts->parent.t,
60c5092c 3039 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3040 LTT_EVENT_SYSCALL_ENTRY,
6418800d 3041 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3042 syscall_entry, NULL, &hooks);
cbe7c836 3043
6418800d 3044 lttv_trace_find_hook(ts->parent.t,
60c5092c 3045 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3046 LTT_EVENT_SYSCALL_EXIT,
032ba5da 3047 NULL,
6418800d 3048 syscall_exit, NULL, &hooks);
cbe7c836 3049
6418800d 3050 lttv_trace_find_hook(ts->parent.t,
60c5092c 3051 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3052 LTT_EVENT_TRAP_ENTRY,
6418800d 3053 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3054 trap_entry, NULL, &hooks);
cbe7c836 3055
032ba5da 3056 lttv_trace_find_hook(ts->parent.t,
60c5092c 3057 LTT_FACILITY_KERNEL_ARCH,
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,
60c5092c 3063 LTT_FACILITY_KERNEL,
0ceef9de 3064 LTT_EVENT_IRQ_ENTRY,
032ba5da 3065 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3066 irq_entry, NULL, &hooks);
cbe7c836 3067
032ba5da 3068 lttv_trace_find_hook(ts->parent.t,
60c5092c 3069 LTT_FACILITY_KERNEL,
0ceef9de 3070 LTT_EVENT_IRQ_EXIT,
032ba5da 3071 NULL,
3072 irq_exit, NULL, &hooks);
cbe7c836 3073
032ba5da 3074 lttv_trace_find_hook(ts->parent.t,
60c5092c 3075 LTT_FACILITY_KERNEL,
0ceef9de 3076 LTT_EVENT_SOFT_IRQ_ENTRY,
032ba5da 3077 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3078 soft_irq_entry, NULL, &hooks);
faf074a3 3079
032ba5da 3080 lttv_trace_find_hook(ts->parent.t,
60c5092c 3081 LTT_FACILITY_KERNEL,
0ceef9de 3082 LTT_EVENT_SOFT_IRQ_EXIT,
032ba5da 3083 NULL,
3084 soft_irq_exit, NULL, &hooks);
faf074a3 3085
032ba5da 3086 lttv_trace_find_hook(ts->parent.t,
60c5092c 3087 LTT_FACILITY_KERNEL,
0ceef9de 3088 LTT_EVENT_SCHED_SCHEDULE,
032ba5da 3089 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3090 LTT_FIELD_PREV_STATE),
3091 schedchange, NULL, &hooks);
cbe7c836 3092
032ba5da 3093 lttv_trace_find_hook(ts->parent.t,
60c5092c 3094 LTT_FACILITY_KERNEL,
0ceef9de 3095 LTT_EVENT_PROCESS_FORK,
032ba5da 3096 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3097 LTT_FIELD_CHILD_TGID),
3098 process_fork, NULL, &hooks);
eed2ef37 3099
032ba5da 3100 lttv_trace_find_hook(ts->parent.t,
60c5092c 3101 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3102 LTT_EVENT_KTHREAD_CREATE,
370231d7 3103 FIELD_ARRAY(LTT_FIELD_PID),
032ba5da 3104 process_kernel_thread, NULL, &hooks);
7bfd7820 3105
032ba5da 3106 lttv_trace_find_hook(ts->parent.t,
60c5092c 3107 LTT_FACILITY_KERNEL,
0ceef9de 3108 LTT_EVENT_PROCESS_EXIT,
032ba5da 3109 FIELD_ARRAY(LTT_FIELD_PID),
3110 process_exit, NULL, &hooks);
eed2ef37 3111
032ba5da 3112 lttv_trace_find_hook(ts->parent.t,
60c5092c 3113 LTT_FACILITY_KERNEL,
0ceef9de 3114 LTT_EVENT_PROCESS_FREE,
032ba5da 3115 FIELD_ARRAY(LTT_FIELD_PID),
3116 process_free, NULL, &hooks);
2cdc690b 3117
032ba5da 3118 lttv_trace_find_hook(ts->parent.t,
43fb1d98 3119 LTT_FACILITY_FS,
0ceef9de 3120 LTT_EVENT_EXEC,
032ba5da 3121 FIELD_ARRAY(LTT_FIELD_FILENAME),
3122 process_exec, NULL, &hooks);
f4b88a7d 3123
032ba5da 3124 lttv_trace_find_hook(ts->parent.t,
60c5092c 3125 LTT_FACILITY_USER_GENERIC,
0ceef9de 3126 LTT_EVENT_THREAD_BRAND,
032ba5da 3127 FIELD_ARRAY(LTT_FIELD_NAME),
3128 thread_brand, NULL, &hooks);
7b5f6cf1 3129
b3fd4c02 3130 /* statedump-related hooks */
032ba5da 3131 lttv_trace_find_hook(ts->parent.t,
60c5092c 3132 LTT_FACILITY_LIST,
0ceef9de 3133 LTT_EVENT_PROCESS_STATE,
d3a66443 3134 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3135 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3136 LTT_FIELD_STATUS, LTT_FIELD_TGID),
032ba5da 3137 enum_process_state, NULL, &hooks);
f4b88a7d 3138
032ba5da 3139 lttv_trace_find_hook(ts->parent.t,
60c5092c 3140 LTT_FACILITY_LIST,
0ceef9de 3141 LTT_EVENT_STATEDUMP_END,
032ba5da 3142 NULL,
3143 statedump_end, NULL, &hooks);
c3b3b60b 3144
032ba5da 3145 lttv_trace_find_hook(ts->parent.t,
60c5092c 3146 LTT_FACILITY_LIST,
0ceef9de 3147 LTT_EVENT_LIST_INTERRUPT,
43fb1d98 3148 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
032ba5da 3149 enum_interrupt, NULL, &hooks);
38b73700 3150
032ba5da 3151 lttv_trace_find_hook(ts->parent.t,
60c5092c 3152 LTT_FACILITY_BLOCK,
0ceef9de 3153 LTT_EVENT_REQUEST_ISSUE,
032ba5da 3154 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3155 bdev_request_issue, NULL, &hooks);
27811799 3156
032ba5da 3157 lttv_trace_find_hook(ts->parent.t,
60c5092c 3158 LTT_FACILITY_BLOCK,
0ceef9de 3159 LTT_EVENT_REQUEST_COMPLETE,
032ba5da 3160 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3161 bdev_request_complete, NULL, &hooks);
27811799 3162
032ba5da 3163 lttv_trace_find_hook(ts->parent.t,
60c5092c 3164 LTT_FACILITY_USER_GENERIC,
0ceef9de 3165 LTT_EVENT_FUNCTION_ENTRY,
032ba5da 3166 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3167 function_entry, NULL, &hooks);
302efbad 3168
032ba5da 3169 lttv_trace_find_hook(ts->parent.t,
60c5092c 3170 LTT_FACILITY_USER_GENERIC,
0ceef9de 3171 LTT_EVENT_FUNCTION_EXIT,
032ba5da 3172 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3173 function_exit, NULL, &hooks);
302efbad 3174
a5ba1787 3175 /* Add these hooks to each event_by_id hooks list */
dc877563 3176
eed2ef37 3177 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3178
dc877563 3179 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3180 tfs =
9d239bd9 3181 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3182 LttvTracefileContext*, j));
dc877563 3183
3184 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3185 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3186 lttv_hooks_add(
5fd4c7a2 3187 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3188 th->h,
3189 th,
eed2ef37 3190 LTTV_PRIO_STATE);
ffd54a90 3191 }
dc877563 3192 }
f0b795e0 3193 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3194 *(val.v_pointer) = hooks;
dc877563 3195 }
3196}
3197
58c88a41 3198gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3199{
3200 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3201
3202 lttv_state_remove_event_hooks(tss);
3203
3204 return 0;
3205}
dc877563 3206
308711e5 3207void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 3208{
ba576a78 3209 LttvTraceset *traceset = self->parent.ts;
dc877563 3210
8979f265 3211 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3212
ba576a78 3213 LttvTraceState *ts;
dc877563 3214
ba576a78 3215 LttvTracefileState *tfs;
dc877563 3216
dc877563 3217 GArray *hooks;
3218
5fd4c7a2 3219 LttvTraceHook *th;
dc877563 3220
3221 LttvAttributeValue val;
3222
ba576a78 3223 nb_trace = lttv_traceset_number(traceset);
dc877563 3224 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 3225 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
7df20ca4 3226
f0b795e0 3227 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3228 hooks = *(val.v_pointer);
dc877563 3229
a5ba1787 3230 /* Remove these hooks from each event_by_id hooks list */
dc877563 3231
eed2ef37 3232 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3233
dc877563 3234 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3235 tfs =
cb03932a 3236 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3237 LttvTracefileContext*, j));
dc877563 3238
3239 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3240 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3241 lttv_hooks_remove_data(
5fd4c7a2 3242 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3243 th->h,
3244 th);
ffd54a90 3245 }
dc877563 3246 }
032ba5da 3247 lttv_trace_hook_remove_all(&hooks);
dc877563 3248 g_array_free(hooks, TRUE);
3249 }
3250}
3251
eed2ef37 3252static gboolean state_save_event_hook(void *hook_data, void *call_data)
3253{
3254 guint *event_count = (guint*)hook_data;
3255
3256 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3257 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3258 return FALSE;
3259 else
18c87975 3260 *event_count = 0;
eed2ef37 3261
3262 LttvTracefileState *self = (LttvTracefileState *)call_data;
3263
eed2ef37 3264 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3265
eed2ef37 3266 LttvAttribute *saved_states_tree, *saved_state_tree;
3267
3268 LttvAttributeValue value;
3269
3270 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3271 LTTV_STATE_SAVED_STATES);
3272 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3273 value = lttv_attribute_add(saved_states_tree,
3274 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3275 *(value.v_gobject) = (GObject *)saved_state_tree;
3276 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3277 *(value.v_time) = self->parent.timestamp;
3278 lttv_state_save(tcs, saved_state_tree);
3279 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3280 self->parent.timestamp.tv_nsec);
3281
3282 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3283
3284 return FALSE;
3285}
3286
14aecf75 3287static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3288{
3289 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3290
3291 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3292
3293 return FALSE;
3294}
3295
ae3d0f50 3296guint lttv_state_current_cpu(LttvTracefileState *tfs)
3297{
80e0221b 3298 return tfs->cpu;
ae3d0f50 3299}
3300
3301
3302
eed2ef37 3303#if 0
08b1c66e 3304static gboolean block_start(void *hook_data, void *call_data)
308711e5 3305{
dbb7bb09 3306 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 3307
dbb7bb09 3308 LttvTracefileState *tfcs;
308711e5 3309
dbb7bb09 3310 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3311
3312 LttEventPosition *ep;
308711e5 3313
dbb7bb09 3314 guint i, nb_block, nb_event, nb_tracefile;
308711e5 3315
3316 LttTracefile *tf;
3317
3318 LttvAttribute *saved_states_tree, *saved_state_tree;
3319
3320 LttvAttributeValue value;
3321
dbb7bb09 3322 ep = ltt_event_position_new();
eed2ef37 3323
3324 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 3325
3326 /* Count the number of events added since the last block end in any
3327 tracefile. */
3328
3329 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 3330 tfcs =
3331 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3332 LttvTracefileContext, i));
dbb7bb09 3333 ltt_event_position(tfcs->parent.e, ep);
3334 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3335 tcs->nb_event += nb_event - tfcs->saved_position;
3336 tfcs->saved_position = nb_event;
3337 }
3338 g_free(ep);
308711e5 3339
308711e5 3340 if(tcs->nb_event >= tcs->save_interval) {
3341 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3342 LTTV_STATE_SAVED_STATES);
3343 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3344 value = lttv_attribute_add(saved_states_tree,
3345 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3346 *(value.v_gobject) = (GObject *)saved_state_tree;
3347 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 3348 *(value.v_time) = self->parent.timestamp;
308711e5 3349 lttv_state_save(tcs, saved_state_tree);
3350 tcs->nb_event = 0;
08b1c66e 3351 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
80e0221b 3352 self->parent.timestamp.tv_nsec);
308711e5 3353 }
dbb7bb09 3354 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 3355 return FALSE;
3356}
eed2ef37 3357#endif //0
308711e5 3358
eed2ef37 3359#if 0
08b1c66e 3360static gboolean block_end(void *hook_data, void *call_data)
3361{
3362 LttvTracefileState *self = (LttvTracefileState *)call_data;
3363
3364 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3365
3366 LttTracefile *tf;
3367
3368 LttEventPosition *ep;
3369
3370 guint nb_block, nb_event;
3371
3372 ep = ltt_event_position_new();
3373 ltt_event_position(self->parent.e, ep);
3374 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3375 tcs->nb_event += nb_event - self->saved_position + 1;
3376 self->saved_position = 0;
3377 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3378 g_free(ep);
00e74b69 3379
3380 return FALSE;
08b1c66e 3381}
eed2ef37 3382#endif //0
3383#if 0
308711e5 3384void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3385{
3386 LttvTraceset *traceset = self->parent.ts;
3387
00e74b69 3388 guint i, j, nb_trace, nb_tracefile;
308711e5 3389
3390 LttvTraceState *ts;
3391
3392 LttvTracefileState *tfs;
3393
08b1c66e 3394 LttvTraceHook hook_start, hook_end;
308711e5 3395
3396 nb_trace = lttv_traceset_number(traceset);
3397 for(i = 0 ; i < nb_trace ; i++) {
3398 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3399
08b1c66e 3400 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3401 NULL, NULL, block_start, &hook_start);
308711e5 3402 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3403 NULL, NULL, block_end, &hook_end);
308711e5 3404
eed2ef37 3405 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3406
dbb7bb09 3407 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3408 tfs =
3409 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3410 LttvTracefileContext, j));
a5ba1787 3411 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3412 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 3413 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3414 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
eed2ef37 3415 }
3416 }
3417}
3418#endif //0
3419
3420void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3421{
3422 LttvTraceset *traceset = self->parent.ts;
3423
3424 guint i, j, nb_trace, nb_tracefile;
3425
3426 LttvTraceState *ts;
3427
3428 LttvTracefileState *tfs;
3429
3430
3431 nb_trace = lttv_traceset_number(traceset);
3432 for(i = 0 ; i < nb_trace ; i++) {
3433
3434 ts = (LttvTraceState *)self->parent.traces[i];
3435 nb_tracefile = ts->parent.tracefiles->len;
3436
ce05e187 3437 if(ts->has_precomputed_states) continue;
3438
3054461a 3439 guint *event_count = g_new(guint, 1);
3440 *event_count = 0;
3441
eed2ef37 3442 for(j = 0 ; j < nb_tracefile ; j++) {
3443 tfs =
cb03932a 3444 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3445 LttvTracefileContext*, j));
eed2ef37 3446 lttv_hooks_add(tfs->parent.event,
3447 state_save_event_hook,
3448 event_count,
3449 LTTV_PRIO_STATE);
3450
308711e5 3451 }
3452 }
14aecf75 3453
3454 lttv_process_traceset_begin(&self->parent,
3455 NULL, NULL, NULL, NULL, NULL);
3456
308711e5 3457}
3458
b56b5fec 3459gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3460{
3461 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3462
3463 lttv_state_save_add_event_hooks(tss);
3464
3465 return 0;
3466}
3467
308711e5 3468
eed2ef37 3469#if 0
308711e5 3470void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3471{
3472 LttvTraceset *traceset = self->parent.ts;
3473
00e74b69 3474 guint i, j, nb_trace, nb_tracefile;
308711e5 3475
3476 LttvTraceState *ts;
3477
3478 LttvTracefileState *tfs;
3479
08b1c66e 3480 LttvTraceHook hook_start, hook_end;
308711e5 3481
3482 nb_trace = lttv_traceset_number(traceset);
3483 for(i = 0 ; i < nb_trace ; i++) {
3484 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 3485
08b1c66e 3486 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3487 NULL, NULL, block_start, &hook_start);
08b1c66e 3488
308711e5 3489 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3490 NULL, NULL, block_end, &hook_end);
308711e5 3491
eed2ef37 3492 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3493
dbb7bb09 3494 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3495 tfs =
3496 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3497 LttvTracefileContext, j));
308711e5 3498 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3499 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 3500 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3501 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 3502 }
3503 }
3504}
eed2ef37 3505#endif //0
3506
3507void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3508{
3509 LttvTraceset *traceset = self->parent.ts;
3510
3511 guint i, j, nb_trace, nb_tracefile;
3512
3513 LttvTraceState *ts;
3514
3515 LttvTracefileState *tfs;
3516
14aecf75 3517 LttvHooks *after_trace = lttv_hooks_new();
3518
3519 lttv_hooks_add(after_trace,
3520 state_save_after_trace_hook,
3521 NULL,
3522 LTTV_PRIO_STATE);
3523
3524
3525 lttv_process_traceset_end(&self->parent,
3526 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 3527
14aecf75 3528 lttv_hooks_destroy(after_trace);
3529
eed2ef37 3530 nb_trace = lttv_traceset_number(traceset);
3531 for(i = 0 ; i < nb_trace ; i++) {
3532
3533 ts = (LttvTraceState *)self->parent.traces[i];
3534 nb_tracefile = ts->parent.tracefiles->len;
3535
ce05e187 3536 if(ts->has_precomputed_states) continue;
3537
22b165e9 3538 guint *event_count = NULL;
eed2ef37 3539
3540 for(j = 0 ; j < nb_tracefile ; j++) {
3541 tfs =
cb03932a 3542 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3543 LttvTracefileContext*, j));
eed2ef37 3544 event_count = lttv_hooks_remove(tfs->parent.event,
3545 state_save_event_hook);
eed2ef37 3546 }
22b165e9 3547 if(event_count) g_free(event_count);
eed2ef37 3548 }
3549}
308711e5 3550
b56b5fec 3551gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3552{
3553 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3554
3555 lttv_state_save_remove_event_hooks(tss);
3556
3557 return 0;
3558}
308711e5 3559
dd025f91 3560void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 3561{
3562 LttvTraceset *traceset = self->parent.ts;
3563
00e74b69 3564 guint i, nb_trace;
308711e5 3565
3566 int min_pos, mid_pos, max_pos;
3567
728d0c3e 3568 guint call_rest = 0;
3569
308711e5 3570 LttvTraceState *tcs;
3571
3572 LttvAttributeValue value;
3573
3574 LttvAttributeType type;
3575
3576 LttvAttributeName name;
3577
80e0221b 3578 gboolean is_named;
c0cb4d12 3579
308711e5 3580 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3581
d448fce2 3582 //g_tree_destroy(self->parent.pqueue);
3583 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 3584
728d0c3e 3585 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3586
308711e5 3587 nb_trace = lttv_traceset_number(traceset);
3588 for(i = 0 ; i < nb_trace ; i++) {
3589 tcs = (LttvTraceState *)self->parent.traces[i];
3590
2a2fa4f0 3591 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3592 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3593 LTTV_STATE_SAVED_STATES);
3594 min_pos = -1;
3595
3596 if(saved_states_tree) {
dd025f91 3597 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3598 mid_pos = max_pos / 2;
3599 while(min_pos < max_pos) {
c0cb4d12 3600 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
80e0221b 3601 &is_named);
dd025f91 3602 g_assert(type == LTTV_GOBJECT);
3603 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3604 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3605 &value);
3606 g_assert(type == LTTV_TIME);
3607 if(ltt_time_compare(*(value.v_time), t) < 0) {
3608 min_pos = mid_pos;
3609 closest_tree = saved_state_tree;
3610 }
3611 else max_pos = mid_pos - 1;
3612
3613 mid_pos = (min_pos + max_pos + 1) / 2;
3614 }
2a2fa4f0 3615 }
dd025f91 3616
2a2fa4f0 3617 /* restore the closest earlier saved state */
f95bc830 3618 if(min_pos != -1) {
3619 lttv_state_restore(tcs, closest_tree);
728d0c3e 3620 call_rest = 1;
f95bc830 3621 }
dd025f91 3622
2a2fa4f0 3623 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 3624 else {
3625 restore_init_state(tcs);
3626 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 3627 }
9444deae 3628 }
dd025f91 3629 /* We want to seek quickly without restoring/updating the state */
3630 else {
308711e5 3631 restore_init_state(tcs);
dd025f91 3632 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 3633 }
308711e5 3634 }
728d0c3e 3635 if(!call_rest) g_info("NOT Calling restore");
308711e5 3636}
3637
3638
3639static void
3640traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3641{
3642}
3643
3644
3645static void
3646traceset_state_finalize (LttvTracesetState *self)
3647{
3648 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3649 finalize(G_OBJECT(self));
3650}
3651
3652
3653static void
3654traceset_state_class_init (LttvTracesetContextClass *klass)
3655{
3656 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3657
3658 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3659 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3660 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3661 klass->new_traceset_context = new_traceset_context;
3662 klass->new_trace_context = new_trace_context;
3663 klass->new_tracefile_context = new_tracefile_context;
3664}
3665
3666
3667GType
3668lttv_traceset_state_get_type(void)
3669{
3670 static GType type = 0;
3671 if (type == 0) {
3672 static const GTypeInfo info = {
3673 sizeof (LttvTracesetStateClass),
3674 NULL, /* base_init */
3675 NULL, /* base_finalize */
3676 (GClassInitFunc) traceset_state_class_init, /* class_init */
3677 NULL, /* class_finalize */
3678 NULL, /* class_data */
dbb7bb09 3679 sizeof (LttvTracesetState),
308711e5 3680 0, /* n_preallocs */
00e74b69 3681 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3682 NULL /* value handling */
308711e5 3683 };
3684
3685 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3686 &info, 0);
3687 }
3688 return type;
3689}
3690
3691
3692static void
3693trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3694{
3695}
3696
3697
3698static void
3699trace_state_finalize (LttvTraceState *self)
3700{
3701 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3702 finalize(G_OBJECT(self));
3703}
3704
3705
3706static void
3707trace_state_class_init (LttvTraceStateClass *klass)
3708{
3709 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3710
3711 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3712 klass->state_save = state_save;
3713 klass->state_restore = state_restore;
3714 klass->state_saved_free = state_saved_free;
3715}
3716
3717
3718GType
3719lttv_trace_state_get_type(void)
3720{
3721 static GType type = 0;
3722 if (type == 0) {
3723 static const GTypeInfo info = {
3724 sizeof (LttvTraceStateClass),
3725 NULL, /* base_init */
3726 NULL, /* base_finalize */
3727 (GClassInitFunc) trace_state_class_init, /* class_init */
3728 NULL, /* class_finalize */
3729 NULL, /* class_data */
3730 sizeof (LttvTraceState),
3731 0, /* n_preallocs */
00e74b69 3732 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3733 NULL /* value handling */
308711e5 3734 };
3735
3736 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3737 "LttvTraceStateType", &info, 0);
3738 }
3739 return type;
3740}
3741
3742
3743static void
3744tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3745{
3746}
3747
3748
3749static void
3750tracefile_state_finalize (LttvTracefileState *self)
3751{
3752 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3753 finalize(G_OBJECT(self));
3754}
3755
3756
3757static void
3758tracefile_state_class_init (LttvTracefileStateClass *klass)
3759{
3760 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3761
3762 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3763}
3764
3765
3766GType
3767lttv_tracefile_state_get_type(void)
3768{
3769 static GType type = 0;
3770 if (type == 0) {
3771 static const GTypeInfo info = {
3772 sizeof (LttvTracefileStateClass),
3773 NULL, /* base_init */
3774 NULL, /* base_finalize */
3775 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3776 NULL, /* class_finalize */
3777 NULL, /* class_data */
3778 sizeof (LttvTracefileState),
3779 0, /* n_preallocs */
00e74b69 3780 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3781 NULL /* value handling */
308711e5 3782 };
3783
3784 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3785 "LttvTracefileStateType", &info, 0);
3786 }
3787 return type;
3788}
3789
3790
08b1c66e 3791static void module_init()
ffd54a90 3792{
83e160f2 3793 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
7b5f6cf1 3794 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
b3fd4c02 3795 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3796 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3797 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3798 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3799 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3800 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3801 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3802 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3803 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3804 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3805 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3806 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3807 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3808 LTTV_STATE_RUN = g_quark_from_string("RUN");
3809 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
80e0221b 3810 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3811 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
308711e5 3812 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3813 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3814 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 3815 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 3816 LTTV_STATE_EVENT = g_quark_from_string("event");
3817 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 3818 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 3819 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 3820 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 3821 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3822 LTTV_STATE_TRACE_STATE_USE_COUNT =
3823 g_quark_from_string("trace_state_use_count");
fbfbd4db 3824 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
98d7814f 3825 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
3826 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
eed2ef37 3827
3828
3829 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 3830 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
f4b88a7d 3831 LTT_FACILITY_FS = g_quark_from_string("fs");
86c32a8f 3832 LTT_FACILITY_LIST = g_quark_from_string("list");
302efbad 3833 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
27811799 3834 LTT_FACILITY_BLOCK = g_quark_from_string("block");
eed2ef37 3835
3836
3837 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3838 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3839 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3840 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3841 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3842 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
43fb1d98 3843 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
3844 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
86c32a8f 3845 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3846 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3847 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3848 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
f63ebe51 3849 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
f4b88a7d 3850 LTT_EVENT_EXEC = g_quark_from_string("exec");
86c32a8f 3851 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
c3b3b60b 3852 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
302efbad 3853 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3854 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
7b5f6cf1 3855 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
27811799 3856 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
3857 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
38b73700 3858 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
eed2ef37 3859
3860
3861 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3862 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3863 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 3864 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
f63ebe51 3865 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3866 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3867 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
eed2ef37 3868 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3869 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3870 LTT_FIELD_PID = g_quark_from_string("pid");
fcc08e1e 3871 LTT_FIELD_TGID = g_quark_from_string("tgid");
f63ebe51 3872 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
f4b88a7d 3873 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 3874 LTT_FIELD_NAME = g_quark_from_string("name");
e62e7f3a 3875 LTT_FIELD_TYPE = g_quark_from_string("type");
b3fd4c02 3876 LTT_FIELD_MODE = g_quark_from_string("mode");
3877 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3878 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 3879 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3880 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
27811799 3881 LTT_FIELD_MAJOR = g_quark_from_string("major");
3882 LTT_FIELD_MINOR = g_quark_from_string("minor");
3883 LTT_FIELD_OPERATION = g_quark_from_string("direction");
38b73700 3884 LTT_FIELD_ACTION = g_quark_from_string("action");
eed2ef37 3885
44ffb95f 3886 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3887 LTTV_CPU_IDLE = g_quark_from_string("idle");
3888 LTTV_CPU_BUSY = g_quark_from_string("busy");
598026ba 3889 LTTV_CPU_IRQ = g_quark_from_string("irq");
d3d99fde 3890 LTTV_CPU_TRAP = g_quark_from_string("trap");
5e563da0 3891
3892 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
3893 LTTV_IRQ_IDLE = g_quark_from_string("idle");
3894 LTTV_IRQ_BUSY = g_quark_from_string("busy");
27811799 3895
3896 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
3897 LTTV_BDEV_IDLE = g_quark_from_string("idle");
3898 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
3899 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
ffd54a90 3900}
dc877563 3901
08b1c66e 3902static void module_destroy()
ffd54a90 3903{
3904}
dc877563 3905
3906
08b1c66e 3907LTTV_MODULE("state", "State computation", \
3908 "Update the system state, possibly saving it at intervals", \
3909 module_init, module_destroy)
3910
dc877563 3911
3912
This page took 0.270968 seconds and 4 git commands to generate.