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