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