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