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