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