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