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