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