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