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