stats major rework, with addition of function support
[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 }
14236daa 1110 return 0;
6806b3c6 1111}
1112
1113static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1114 guint pid, const LttTime *timestamp)
1115{
1116 LttvTracefileState *tfs = NULL;
1117 struct search_result res;
1118 /* Find the usertrace associated with a pid and time interval.
1119 * Search in the usertraces by PID (within a hash) and then, for each
1120 * corresponding element of the array, find the first one with creation
1121 * timestamp the lowest, but higher or equal to "timestamp". */
1122 res.time = timestamp;
1123 res.best = NULL;
1124 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1125 if(usertrace_tree) {
1126 g_tree_search(usertrace_tree, search_usertrace, &res);
1127 if(res.best)
1128 tfs = g_tree_lookup(usertrace_tree, res.best);
1129 }
1130
1131 return tfs;
1132}
1133
dc877563 1134
2a2fa4f0 1135LttvProcessState *
348c6ba8 1136lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
b3fd4c02 1137 guint cpu, guint pid, GQuark name, const LttTime *timestamp)
dc877563 1138{
1139 LttvProcessState *process = g_new(LttvProcessState, 1);
1140
b445142a 1141 LttvExecutionState *es;
dc877563 1142
348c6ba8 1143 LttvTraceContext *tc = (LttvTraceContext*)tcs;
ba576a78 1144
b445142a 1145 char buffer[128];
ffd54a90 1146
dc877563 1147 process->pid = pid;
348c6ba8 1148 process->cpu = cpu;
b3fd4c02 1149 process->name = name;
348c6ba8 1150 //process->last_cpu = tfs->cpu_name;
1151 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
7bfd7820 1152 process->kernel_thread = 0;
6806b3c6 1153 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
302efbad 1154 process->current_function = 0; //function 0x0 by default.
7bfd7820 1155
cb03932a 1156 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 1157 g_hash_table_insert(tcs->processes, process, process);
b445142a 1158
1159 if(parent) {
1160 process->ppid = parent->pid;
348c6ba8 1161 process->creation_time = *timestamp;
b445142a 1162 }
2a2fa4f0 1163
1164 /* No parent. This process exists but we are missing all information about
1165 its creation. The birth time is set to zero but we remember the time of
1166 insertion */
1167
b445142a 1168 else {
1169 process->ppid = 0;
2a2fa4f0 1170 process->creation_time = ltt_time_zero;
b445142a 1171 }
1172
348c6ba8 1173 process->insertion_time = *timestamp;
b445142a 1174 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1175 process->creation_time.tv_nsec);
1176 process->pid_time = g_quark_from_string(buffer);
348c6ba8 1177 process->cpu = cpu;
1178 //process->last_cpu = tfs->cpu_name;
1179 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 1180 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1181 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
c607371b 1182 process->execution_stack = g_array_set_size(process->execution_stack, 2);
b445142a 1183 es = process->state = &g_array_index(process->execution_stack,
1184 LttvExecutionState, 0);
1185 es->t = LTTV_STATE_USER_MODE;
1186 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 1187 es->entry = *timestamp;
1188 //g_assert(timestamp->tv_sec != 0);
1189 es->change = *timestamp;
c607371b 1190 es->s = LTTV_STATE_RUN;
1191
1192 es = process->state = &g_array_index(process->execution_stack,
1193 LttvExecutionState, 1);
1194 es->t = LTTV_STATE_SYSCALL;
1195 es->n = LTTV_STATE_SUBMODE_NONE;
1196 es->entry = *timestamp;
1197 //g_assert(timestamp->tv_sec != 0);
1198 es->change = *timestamp;
b445142a 1199 es->s = LTTV_STATE_WAIT_FORK;
302efbad 1200
1201 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1202 process->user_stack = g_array_sized_new(FALSE, FALSE,
1203 sizeof(guint64), 0);
1204
cbe7c836 1205 return process;
dc877563 1206}
1207
348c6ba8 1208LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 1209 guint pid)
dc877563 1210{
2a2fa4f0 1211 LttvProcessState key;
1212 LttvProcessState *process;
1213
1214 key.pid = pid;
348c6ba8 1215 key.cpu = cpu;
2a2fa4f0 1216 process = g_hash_table_lookup(ts->processes, &key);
dc877563 1217 return process;
1218}
1219
2a2fa4f0 1220LttvProcessState *
348c6ba8 1221lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1222 LttTime *timestamp)
2a2fa4f0 1223{
348c6ba8 1224 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
7bfd7820 1225 LttvExecutionState *es;
348c6ba8 1226
1227 /* Put ltt_time_zero creation time for unexisting processes */
7bfd7820 1228 if(unlikely(process == NULL)) {
1229 process = lttv_state_create_process(ts,
b3fd4c02 1230 NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
7bfd7820 1231 /* We are not sure is it's a kernel thread or normal thread, put the
1232 * bottom stack state to unknown */
1233 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1234 es->t = LTTV_STATE_MODE_UNKNOWN;
1235 }
2a2fa4f0 1236 return process;
1237}
1238
41c7f803 1239/* FIXME : this function should be called when we receive an event telling that
1240 * release_task has been called in the kernel. In happens generally when
1241 * the parent waits for its child terminaison, but may also happen in special
1242 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1243 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1244 * of a killed thread ground, but isn't the leader.
41c7f803 1245 */
b445142a 1246static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 1247{
ba576a78 1248 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 1249 LttvProcessState key;
ba576a78 1250
2a2fa4f0 1251 key.pid = process->pid;
348c6ba8 1252 key.cpu = process->cpu;
2a2fa4f0 1253 g_hash_table_remove(ts->processes, &key);
b445142a 1254 g_array_free(process->execution_stack, TRUE);
302efbad 1255 g_array_free(process->user_stack, TRUE);
dc877563 1256 g_free(process);
1257}
1258
1259
b445142a 1260static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 1261{
b445142a 1262 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
302efbad 1263 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
dc877563 1264 g_free(value);
1265}
1266
1267
308711e5 1268static void lttv_state_free_process_table(GHashTable *processes)
dc877563 1269{
1270 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 1271 g_hash_table_destroy(processes);
dc877563 1272}
1273
1274
b445142a 1275static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 1276{
ba576a78 1277 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1278 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1279 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1280 LttField *f = thf->f1;
dc877563 1281
b445142a 1282 LttvExecutionSubmode submode;
1283
7cd289b0 1284 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1285 guint syscall = ltt_event_get_unsigned(e, f);
1286
1287 if(syscall < nb_syscalls) {
1288 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1289 syscall];
1290 } else {
1291 /* Fixup an incomplete syscall table */
1292 GString *string = g_string_new("");
1293 g_string_printf(string, "syscall %u", syscall);
1294 submode = g_quark_from_string(string->str);
1295 g_string_free(string, TRUE);
1296 }
b445142a 1297 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 1298 return FALSE;
1299}
1300
1301
b445142a 1302static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 1303{
ba576a78 1304 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1305
ffd54a90 1306 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 1307 return FALSE;
1308}
1309
1310
b445142a 1311static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 1312{
ba576a78 1313 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1314 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1315 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1316 LttField *f = thf->f1;
dc877563 1317
b445142a 1318 LttvExecutionSubmode submode;
1319
1320 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
eed2ef37 1321 ltt_event_get_unsigned(e, f)];
b445142a 1322 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 1323 return FALSE;
1324}
1325
1326
b445142a 1327static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 1328{
ba576a78 1329 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1330
ffd54a90 1331 pop_state(s, LTTV_STATE_TRAP);
dc877563 1332 return FALSE;
1333}
1334
1335
b445142a 1336static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 1337{
ba576a78 1338 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1339 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 1340 guint8 fac_id = ltt_event_facility_id(e);
1341 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 1342 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 1343 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1344 g_assert(thf->f1 != NULL);
1345 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 1346 LttField *f = thf->f1;
dc877563 1347
b445142a 1348 LttvExecutionSubmode submode;
1349
1350 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
eed2ef37 1351 ltt_event_get_unsigned(e, f)];
b445142a 1352
dc877563 1353 /* Do something with the info about being in user or system mode when int? */
b445142a 1354 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 1355 return FALSE;
1356}
1357
302efbad 1358static gboolean soft_irq_exit(void *hook_data, void *call_data)
1359{
1360 LttvTracefileState *s = (LttvTracefileState *)call_data;
1361
1362 pop_state(s, LTTV_STATE_SOFT_IRQ);
1363 return FALSE;
1364}
1365
1366
dc877563 1367
b445142a 1368static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 1369{
ba576a78 1370 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1371
ffd54a90 1372 pop_state(s, LTTV_STATE_IRQ);
dc877563 1373 return FALSE;
1374}
1375
faf074a3 1376static gboolean soft_irq_entry(void *hook_data, void *call_data)
1377{
1378 LttvTracefileState *s = (LttvTracefileState *)call_data;
1379 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1380 guint8 fac_id = ltt_event_facility_id(e);
1381 guint8 ev_id = ltt_event_eventtype_id(e);
1382 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1383 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1384 g_assert(thf->f1 != NULL);
1385 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1386 LttField *f = thf->f1;
1387
1388 LttvExecutionSubmode submode;
1389
1390 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1391 ltt_event_get_unsigned(e, f)];
1392
1393 /* Do something with the info about being in user or system mode when int? */
1394 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1395 return FALSE;
1396}
1397
302efbad 1398static void push_function(LttvTracefileState *tfs, guint64 funcptr)
1399{
1400 guint64 *new_func;
1401
1402 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1403 guint cpu = tfs->cpu;
1404 LttvProcessState *process = ts->running_process[cpu];
faf074a3 1405
302efbad 1406 guint depth = process->user_stack->len;
1407
1408 process->user_stack =
1409 g_array_set_size(process->user_stack, depth + 1);
1410
1411 new_func = &g_array_index(process->user_stack, guint64, depth);
1412 *new_func = funcptr;
1413 process->current_function =
1414 g_array_index(process->user_stack, guint64, depth - 1);
1415}
1416
1417static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
1418{
1419 guint cpu = tfs->cpu;
1420 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1421 LttvProcessState *process = ts->running_process[cpu];
1422
1423 guint depth = process->user_stack->len;
1424 if(process->current_function != funcptr){
1425 g_info("Different functions (%lu.%09lu): ignore it\n",
1426 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1427 g_info("process state has %llu when pop_function is %llu\n",
1428 process->current_function, funcptr);
1429 g_info("{ %u, %u, %s, %s }\n",
1430 process->pid,
1431 process->ppid,
1432 g_quark_to_string(process->name),
1433 g_quark_to_string(process->state->s));
1434 return;
1435 }
1436
1437 if(depth == 0){
1438 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1439 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1440 return;
1441 }
1442
1443 process->user_stack =
1444 g_array_set_size(process->user_stack, depth - 1);
1445 process->current_function =
1446 g_array_index(process->user_stack, guint64, depth - 2);
1447}
1448
1449
1450static gboolean function_entry(void *hook_data, void *call_data)
faf074a3 1451{
1452 LttvTracefileState *s = (LttvTracefileState *)call_data;
302efbad 1453 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1454 guint8 fac_id = ltt_event_facility_id(e);
1455 guint8 ev_id = ltt_event_eventtype_id(e);
1456 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1457 g_assert(thf->f1 != NULL);
1458 LttField *f = thf->f1;
1459 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
faf074a3 1460
302efbad 1461 push_function(s, funcptr);
faf074a3 1462 return FALSE;
1463}
1464
302efbad 1465static gboolean function_exit(void *hook_data, void *call_data)
1466{
1467 LttvTracefileState *s = (LttvTracefileState *)call_data;
1468 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1469 guint8 fac_id = ltt_event_facility_id(e);
1470 guint8 ev_id = ltt_event_eventtype_id(e);
1471 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1472 g_assert(thf->f1 != NULL);
1473 LttField *f = thf->f1;
1474 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1475
1476 LttvExecutionSubmode submode;
1477
1478 pop_function(s, funcptr);
1479 return FALSE;
1480}
dc877563 1481
b445142a 1482static gboolean schedchange(void *hook_data, void *call_data)
dc877563 1483{
ba576a78 1484 LttvTracefileState *s = (LttvTracefileState *)call_data;
ae3d0f50 1485 guint cpu = s->cpu;
348c6ba8 1486 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1487 LttvProcessState *process = ts->running_process[cpu];
48b002b8 1488 LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 1489
eed2ef37 1490 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1491 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 1492 guint pid_in, pid_out;
1493 gint state_out;
dc877563 1494
eed2ef37 1495 pid_out = ltt_event_get_unsigned(e, thf->f1);
1496 pid_in = ltt_event_get_unsigned(e, thf->f2);
73394fd3 1497 state_out = ltt_event_get_int(e, thf->f3);
348c6ba8 1498
1499 if(likely(process != NULL)) {
b445142a 1500
f95bc830 1501 /* We could not know but it was not the idle process executing.
1502 This should only happen at the beginning, before the first schedule
1503 event, and when the initial information (current process for each CPU)
1504 is missing. It is not obvious how we could, after the fact, compensate
1505 the wrongly attributed statistics. */
1506
240f1fea 1507 //This test only makes sense once the state is known and if there is no
48b002b8 1508 //missing events. We need to silently ignore schedchange coming after a
1509 //process_free, or it causes glitches. (FIXME)
348c6ba8 1510 //if(unlikely(process->pid != pid_out)) {
1511 // g_assert(process->pid == 0);
240f1fea 1512 //}
f95bc830 1513
348c6ba8 1514 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1515 process->state->s = LTTV_STATE_ZOMBIE;
791dffa6 1516 process->state->change = s->parent.timestamp;
dbd243b1 1517 } else {
348c6ba8 1518 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1519 else process->state->s = LTTV_STATE_WAIT;
791dffa6 1520 process->state->change = s->parent.timestamp;
1521 }
48b002b8 1522
1523 if(state_out == 32)
791dffa6 1524 exit_process(s, process); /* EXIT_DEAD */
1525 /* see sched.h for states */
dc877563 1526 }
348c6ba8 1527 process = ts->running_process[cpu] =
1528 lttv_state_find_process_or_create(
1529 (LttvTraceState*)s->parent.t_context,
1530 cpu, pid_in,
1531 &s->parent.timestamp);
1532 process->state->s = LTTV_STATE_RUN;
1533 process->cpu = cpu;
ae3d0f50 1534 if(process->usertrace)
1535 process->usertrace->cpu = cpu;
348c6ba8 1536 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1537 process->state->change = s->parent.timestamp;
dc877563 1538 return FALSE;
1539}
1540
eed2ef37 1541static gboolean process_fork(void *hook_data, void *call_data)
dc877563 1542{
eed2ef37 1543 LttvTracefileState *s = (LttvTracefileState *)call_data;
1544 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1545 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1546 guint parent_pid;
2cdc690b 1547 guint child_pid;
4ad73431 1548 LttvProcessState *zombie_process;
ae3d0f50 1549 guint cpu = s->cpu;
348c6ba8 1550 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1551 LttvProcessState *process = ts->running_process[cpu];
26275aa2 1552 LttvProcessState *child_process;
2cdc690b 1553
eed2ef37 1554 /* Parent PID */
b3fd4c02 1555 parent_pid = ltt_event_get_unsigned(e, thf->f1);
eed2ef37 1556
2cdc690b 1557 /* Child PID */
b3fd4c02 1558 child_pid = ltt_event_get_unsigned(e, thf->f2);
2cdc690b 1559
15b3d537 1560 /* Mathieu : it seems like the process might have been scheduled in before the
1561 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 1562 * in a SMP case where we don't have enough precision on the clocks.
1563 *
1564 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 1565#if 0
348c6ba8 1566 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 1567
1d1df11d 1568 if(unlikely(zombie_process != NULL)) {
4ad73431 1569 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 1570 * has been released. FIXME : should know when release_task happens instead.
4ad73431 1571 */
15b3d537 1572 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1573 guint i;
1574 for(i=0; i< num_cpus; i++) {
5ac05980 1575 g_assert(zombie_process != ts->running_process[i]);
15b3d537 1576 }
1577
4ad73431 1578 exit_process(s, zombie_process);
1579 }
791dffa6 1580#endif //0
348c6ba8 1581 g_assert(process->pid != child_pid);
eed2ef37 1582 // FIXME : Add this test in the "known state" section
348c6ba8 1583 // g_assert(process->pid == parent_pid);
26275aa2 1584 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1585 if(child_process == NULL) {
ab893fb1 1586 child_process = lttv_state_create_process(ts, process, cpu,
b3fd4c02 1587 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 1588 } else {
1589 /* The process has already been created : due to time imprecision between
791dffa6 1590 * multiple CPUs : it has been scheduled in before creation. Note that we
1591 * shouldn't have this kind of imprecision.
26275aa2 1592 *
1593 * Simply put a correct parent.
1594 */
6806b3c6 1595 g_assert(0); /* This is a problematic case : the process has been created
1596 before the fork event */
26275aa2 1597 child_process->ppid = process->pid;
1598 }
ab893fb1 1599 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1600 child_process->name = process->name;
4ad73431 1601
dc877563 1602 return FALSE;
1603}
1604
7bfd7820 1605/* We stamp a newly created process as kernel_thread */
1606static gboolean process_kernel_thread(void *hook_data, void *call_data)
1607{
1608 LttvTracefileState *s = (LttvTracefileState *)call_data;
1609 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1610 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1611 guint pid;
ae3d0f50 1612 guint cpu = s->cpu;
7bfd7820 1613 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1614 LttvProcessState *process;
1615 LttvExecutionState *es;
1616
1617 /* PID */
1618 pid = ltt_event_get_unsigned(e, thf->f1);
1619
1620 process = lttv_state_find_process(ts, ANY_CPU, pid);
1621 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1622 es->t = LTTV_STATE_SYSCALL;
1623 process->kernel_thread = 1;
1624
1625 return FALSE;
1626}
dc877563 1627
eed2ef37 1628static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1629{
eed2ef37 1630 LttvTracefileState *s = (LttvTracefileState *)call_data;
1631 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1632 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1633 LttField *f;
1634 guint pid;
ae3d0f50 1635 guint cpu = s->cpu;
348c6ba8 1636 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1637 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1638
1639 pid = ltt_event_get_unsigned(e, thf->f1);
1640
1641 // FIXME : Add this test in the "known state" section
348c6ba8 1642 // g_assert(process->pid == pid);
eed2ef37 1643
348c6ba8 1644 if(likely(process != NULL)) {
1645 process->state->s = LTTV_STATE_EXIT;
2cdc690b 1646 }
1647 return FALSE;
2cdc690b 1648}
1649
eed2ef37 1650static gboolean process_free(void *hook_data, void *call_data)
2da61677 1651{
eed2ef37 1652 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1653 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 1654 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1655 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 1656 guint release_pid;
1657 LttvProcessState *process;
1658
1659 /* PID of the process to release */
eed2ef37 1660 release_pid = ltt_event_get_unsigned(e, thf->f1);
15b3d537 1661
1662 g_assert(release_pid != 0);
2da61677 1663
348c6ba8 1664 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 1665
1666 if(likely(process != NULL)) {
1667 /* release_task is happening at kernel level : we can now safely release
1668 * the data structure of the process */
5562ddce 1669 //This test is fun, though, as it may happen that
1670 //at time t : CPU 0 : process_free
1671 //at time t+150ns : CPU 1 : schedule out
1672 //Clearly due to time imprecision, we disable it. (Mathieu)
1673 //If this weird case happen, we have no choice but to put the
1674 //Currently running process on the cpu to 0.
791dffa6 1675 //I re-enable it following time precision fixes. (Mathieu)
1676 //Well, in the case where an process is freed by a process on another CPU
1677 //and still scheduled, it happens that this is the schedchange that will
1678 //drop the last reference count. Do not free it here!
0bd2f89c 1679 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1680 guint i;
1681 for(i=0; i< num_cpus; i++) {
5562ddce 1682 //g_assert(process != ts->running_process[i]);
1683 if(process == ts->running_process[i]) {
791dffa6 1684 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1685 break;
5562ddce 1686 }
0bd2f89c 1687 }
48b002b8 1688 //if(i == num_cpus) /* process is not scheduled */
1689 //exit_process(s, process); // do nothing : wait for the schedchange to
1690 //delete the process.
2da61677 1691 }
1692
1693 return FALSE;
1694}
1695
f4b88a7d 1696
1697static gboolean process_exec(void *hook_data, void *call_data)
1698{
1699 LttvTracefileState *s = (LttvTracefileState *)call_data;
1700 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1701 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1702 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
743e50fd 1703 //gchar *name;
ae3d0f50 1704 guint cpu = s->cpu;
f4b88a7d 1705 LttvProcessState *process = ts->running_process[cpu];
1706
1707 /* PID of the process to release */
743e50fd 1708 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1709 //name = ltt_event_get_string(e, thf->f1);
f2923fb2 1710 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1711 gchar *name_begin =
1712 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 1713 gchar *null_term_name = g_new(gchar, name_len+1);
1714 memcpy(null_term_name, name_begin, name_len);
1715 null_term_name[name_len] = '\0';
1716
1717 process->name = g_quark_from_string(null_term_name);
f2923fb2 1718 g_free(null_term_name);
f4b88a7d 1719 return FALSE;
1720}
1721
b3fd4c02 1722static gboolean enum_process_state(void *hook_data, void *call_data)
1723{
1724 LttvTracefileState *s = (LttvTracefileState *)call_data;
1725 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1726 //It's slow : optimise later by doing this before reading trace.
1727 LttEventType *et = ltt_event_eventtype(e);
1728 //
1729 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1730 guint parent_pid;
1731 guint pid;
1732 gchar * command;
ae3d0f50 1733 guint cpu = s->cpu;
b3fd4c02 1734 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1735 LttvProcessState *process = ts->running_process[cpu];
1736 LttvProcessState *parent_process;
1737 LttField *f4, *f5, *f6;
1738 GQuark mode, submode, status;
f4b88a7d 1739
b3fd4c02 1740 /* PID */
1741 pid = ltt_event_get_unsigned(e, thf->f1);
f4b88a7d 1742
b3fd4c02 1743 /* Parent PID */
1744 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1745
1746 /* Command name */
1747 command = ltt_event_get_string(e, thf->f3);
1748
1749 /* mode */
1750 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1751 mode = ltt_enum_string_get(ltt_field_type(f4),
1752 ltt_event_get_unsigned(e, f4));
1753
1754 /* submode */
1755 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1756 submode = ltt_enum_string_get(ltt_field_type(f5),
1757 ltt_event_get_unsigned(e, f5));
1758
1759 /* status */
1760 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1761 status = ltt_enum_string_get(ltt_field_type(f6),
1762 ltt_event_get_unsigned(e, f6));
1763
1764 /* The process might exist if a process was forked while performing the sate dump. */
1765 process = lttv_state_find_process(ts, ANY_CPU, pid);
1766 if(process == NULL) {
1767 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1768 process = lttv_state_create_process(ts, parent_process, cpu,
1769 pid, g_quark_from_string(command),
1770 &s->parent.timestamp);
1771
1772 /* Keep the stack bottom : a running user mode */
ab893fb1 1773#if 0
1774 /* Disabled because of inconsistencies in the current statedump states. */
b3fd4c02 1775 if(mode == LTTV_STATE_USER_MODE) {
1776 /* Only keep the bottom */
1777 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1778 } else {
1779 /* On top of it : */
1780 LttvExecutionState *es;
1781 es = process->state = &g_array_index(process->execution_stack,
1782 LttvExecutionState, 1);
1783 es->t = mode;
1784 es->s = status;
1785 es->n = submode;
1786 }
ab893fb1 1787#endif //0
b3fd4c02 1788
ab893fb1 1789 /* UNKNOWN STATE */
1790 {
1791 LttvExecutionState *es;
1792 es = process->state = &g_array_index(process->execution_stack,
1793 LttvExecutionState, 1);
1794 es->t = LTTV_STATE_MODE_UNKNOWN;
1795 es->s = LTTV_STATE_UNNAMED;
1796 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1797 }
b3fd4c02 1798 } else {
1799 /* The process has already been created :
1800 * Probably was forked while dumping the process state or
1801 * was simply scheduled in prior to get the state dump event.
1802 */
1803 process->ppid = parent_pid;
1804 process->name = g_quark_from_string(command);
1805 /* Don't mess around with the stack, it will eventually become
1806 * ok after the end of state dump. */
1807 }
1808
1809 return FALSE;
1810}
f4b88a7d 1811
58c88a41 1812gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1813{
1814 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1815
1816 lttv_state_add_event_hooks(tss);
1817
1818 return 0;
1819}
dc877563 1820
308711e5 1821void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1822{
ba576a78 1823 LttvTraceset *traceset = self->parent.ts;
dc877563 1824
eed2ef37 1825 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1826
ba576a78 1827 LttvTraceState *ts;
dc877563 1828
ba576a78 1829 LttvTracefileState *tfs;
dc877563 1830
dc877563 1831 GArray *hooks;
1832
eed2ef37 1833 LttvTraceHookByFacility *thf;
1834
1835 LttvTraceHook *hook;
dc877563 1836
1837 LttvAttributeValue val;
1838
9d239bd9 1839 gint ret;
302efbad 1840 gint hn;
9d239bd9 1841
ba576a78 1842 nb_trace = lttv_traceset_number(traceset);
dc877563 1843 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1844 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1845
1846 /* Find the eventtype id for the following events and register the
1847 associated by id hooks. */
1848
302efbad 1849 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
1850 hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
1851 hn = 0;
b445142a 1852
9d239bd9 1853 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 1854 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 1855 LTT_FIELD_SYSCALL_ID, 0, 0,
302efbad 1856 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1857 if(ret) hn--;
cbe7c836 1858
9d239bd9 1859 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 1860 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
eed2ef37 1861 0, 0, 0,
302efbad 1862 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1863 if(ret) hn--;
cbe7c836 1864
9d239bd9 1865 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1866 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1867 LTT_FIELD_TRAP_ID, 0, 0,
302efbad 1868 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1869 if(ret) hn--;
cbe7c836 1870
9d239bd9 1871 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1872 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1873 0, 0, 0,
302efbad 1874 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1875 if(ret) hn--;
cbe7c836 1876
9d239bd9 1877 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1878 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1879 LTT_FIELD_IRQ_ID, 0, 0,
302efbad 1880 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1881 if(ret) hn--;
cbe7c836 1882
9d239bd9 1883 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1884 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1885 0, 0, 0,
302efbad 1886 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1887 if(ret) hn--;
cbe7c836 1888
faf074a3 1889 ret = lttv_trace_find_hook(ts->parent.t,
1890 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1891 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
302efbad 1892 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1893 if(ret) hn--;
faf074a3 1894
1895 ret = lttv_trace_find_hook(ts->parent.t,
1896 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1897 0, 0, 0,
302efbad 1898 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1899 if(ret) hn--;
faf074a3 1900
9d239bd9 1901 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1902 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1903 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
302efbad 1904 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1905 if(ret) hn--;
cbe7c836 1906
9d239bd9 1907 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1908 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1909 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
302efbad 1910 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1911 if(ret) hn--;
eed2ef37 1912
7bfd7820 1913 ret = lttv_trace_find_hook(ts->parent.t,
1914 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1915 LTT_FIELD_PID, 0, 0,
302efbad 1916 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
1917 hn++));
1918 if(ret) hn--;
7bfd7820 1919
9d239bd9 1920 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1921 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1922 LTT_FIELD_PID, 0, 0,
302efbad 1923 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1924 if(ret) hn--;
eed2ef37 1925
9d239bd9 1926 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1927 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1928 LTT_FIELD_PID, 0, 0,
302efbad 1929 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1930 if(ret) hn--;
2cdc690b 1931
f4b88a7d 1932 ret = lttv_trace_find_hook(ts->parent.t,
1933 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1934 LTT_FIELD_FILENAME, 0, 0,
302efbad 1935 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1936 if(ret) hn--;
f4b88a7d 1937
b3fd4c02 1938 /* statedump-related hooks */
1939 ret = lttv_trace_find_hook(ts->parent.t,
1940 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1941 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
302efbad 1942 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1943 if(ret) hn--;
f4b88a7d 1944
302efbad 1945 ret = lttv_trace_find_hook(ts->parent.t,
1946 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
1947 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1948 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1949 if(ret) hn--;
1950
1951 ret = lttv_trace_find_hook(ts->parent.t,
1952 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
1953 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1954 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1955 if(ret) hn--;
1956
1957 hooks = g_array_set_size(hooks, hn);
1958
a5ba1787 1959 /* Add these hooks to each event_by_id hooks list */
dc877563 1960
eed2ef37 1961 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1962
dc877563 1963 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1964 tfs =
9d239bd9 1965 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1966 LttvTracefileContext*, j));
dc877563 1967
1968 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1969 hook = &g_array_index(hooks, LttvTraceHook, k);
1970 for(l=0;l<hook->fac_list->len;l++) {
1971 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1972 lttv_hooks_add(
1973 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1974 thf->h,
d052ffc3 1975 thf,
eed2ef37 1976 LTTV_PRIO_STATE);
1977 }
ffd54a90 1978 }
dc877563 1979 }
f0b795e0 1980 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 1981 *(val.v_pointer) = hooks;
dc877563 1982 }
1983}
1984
58c88a41 1985gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1986{
1987 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1988
1989 lttv_state_remove_event_hooks(tss);
1990
1991 return 0;
1992}
dc877563 1993
308711e5 1994void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1995{
ba576a78 1996 LttvTraceset *traceset = self->parent.ts;
dc877563 1997
eed2ef37 1998 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1999
ba576a78 2000 LttvTraceState *ts;
dc877563 2001
ba576a78 2002 LttvTracefileState *tfs;
dc877563 2003
dc877563 2004 GArray *hooks;
2005
eed2ef37 2006 LttvTraceHook *hook;
2007
2008 LttvTraceHookByFacility *thf;
dc877563 2009
2010 LttvAttributeValue val;
2011
ba576a78 2012 nb_trace = lttv_traceset_number(traceset);
dc877563 2013 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 2014 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
f0b795e0 2015 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 2016 hooks = *(val.v_pointer);
dc877563 2017
a5ba1787 2018 /* Remove these hooks from each event_by_id hooks list */
dc877563 2019
eed2ef37 2020 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 2021
dc877563 2022 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2023 tfs =
cb03932a 2024 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2025 LttvTracefileContext*, j));
dc877563 2026
2027 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 2028 hook = &g_array_index(hooks, LttvTraceHook, k);
2029 for(l=0;l<hook->fac_list->len;l++) {
2030 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2031
2032 lttv_hooks_remove_data(
2033 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2034 thf->h,
d052ffc3 2035 thf);
eed2ef37 2036 }
ffd54a90 2037 }
dc877563 2038 }
1986f254 2039 for(k = 0 ; k < hooks->len ; k++)
2040 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 2041 g_array_free(hooks, TRUE);
2042 }
2043}
2044
eed2ef37 2045static gboolean state_save_event_hook(void *hook_data, void *call_data)
2046{
2047 guint *event_count = (guint*)hook_data;
2048
2049 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2050 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2051 return FALSE;
2052 else
18c87975 2053 *event_count = 0;
eed2ef37 2054
2055 LttvTracefileState *self = (LttvTracefileState *)call_data;
2056
2057 LttvTracefileState *tfcs;
2058
2059 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2060
2061 LttEventPosition *ep;
2062
2063 guint i;
2064
2065 LttTracefile *tf;
2066
2067 LttvAttribute *saved_states_tree, *saved_state_tree;
2068
2069 LttvAttributeValue value;
2070
2071 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2072 LTTV_STATE_SAVED_STATES);
2073 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2074 value = lttv_attribute_add(saved_states_tree,
2075 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2076 *(value.v_gobject) = (GObject *)saved_state_tree;
2077 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2078 *(value.v_time) = self->parent.timestamp;
2079 lttv_state_save(tcs, saved_state_tree);
2080 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2081 self->parent.timestamp.tv_nsec);
2082
2083 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2084
2085 return FALSE;
2086}
2087
14aecf75 2088static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2089{
2090 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2091
2092 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2093
2094 return FALSE;
2095}
2096
ae3d0f50 2097guint lttv_state_current_cpu(LttvTracefileState *tfs)
2098{
2099 return tfs->cpu;
2100}
2101
2102
2103
eed2ef37 2104#if 0
08b1c66e 2105static gboolean block_start(void *hook_data, void *call_data)
308711e5 2106{
dbb7bb09 2107 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 2108
dbb7bb09 2109 LttvTracefileState *tfcs;
308711e5 2110
dbb7bb09 2111 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2112
2113 LttEventPosition *ep;
308711e5 2114
dbb7bb09 2115 guint i, nb_block, nb_event, nb_tracefile;
308711e5 2116
2117 LttTracefile *tf;
2118
2119 LttvAttribute *saved_states_tree, *saved_state_tree;
2120
2121 LttvAttributeValue value;
2122
dbb7bb09 2123 ep = ltt_event_position_new();
eed2ef37 2124
2125 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 2126
2127 /* Count the number of events added since the last block end in any
2128 tracefile. */
2129
2130 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 2131 tfcs =
2132 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2133 LttvTracefileContext, i));
dbb7bb09 2134 ltt_event_position(tfcs->parent.e, ep);
2135 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2136 tcs->nb_event += nb_event - tfcs->saved_position;
2137 tfcs->saved_position = nb_event;
2138 }
2139 g_free(ep);
308711e5 2140
308711e5 2141 if(tcs->nb_event >= tcs->save_interval) {
2142 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2143 LTTV_STATE_SAVED_STATES);
2144 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2145 value = lttv_attribute_add(saved_states_tree,
2146 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2147 *(value.v_gobject) = (GObject *)saved_state_tree;
2148 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 2149 *(value.v_time) = self->parent.timestamp;
308711e5 2150 lttv_state_save(tcs, saved_state_tree);
2151 tcs->nb_event = 0;
08b1c66e 2152 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2153 self->parent.timestamp.tv_nsec);
308711e5 2154 }
dbb7bb09 2155 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 2156 return FALSE;
2157}
eed2ef37 2158#endif //0
308711e5 2159
eed2ef37 2160#if 0
08b1c66e 2161static gboolean block_end(void *hook_data, void *call_data)
2162{
2163 LttvTracefileState *self = (LttvTracefileState *)call_data;
2164
2165 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2166
2167 LttTracefile *tf;
2168
2169 LttEventPosition *ep;
2170
2171 guint nb_block, nb_event;
2172
2173 ep = ltt_event_position_new();
2174 ltt_event_position(self->parent.e, ep);
2175 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2176 tcs->nb_event += nb_event - self->saved_position + 1;
2177 self->saved_position = 0;
2178 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2179 g_free(ep);
00e74b69 2180
2181 return FALSE;
08b1c66e 2182}
eed2ef37 2183#endif //0
2184#if 0
308711e5 2185void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2186{
2187 LttvTraceset *traceset = self->parent.ts;
2188
00e74b69 2189 guint i, j, nb_trace, nb_tracefile;
308711e5 2190
2191 LttvTraceState *ts;
2192
2193 LttvTracefileState *tfs;
2194
08b1c66e 2195 LttvTraceHook hook_start, hook_end;
308711e5 2196
2197 nb_trace = lttv_traceset_number(traceset);
2198 for(i = 0 ; i < nb_trace ; i++) {
2199 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 2200
08b1c66e 2201 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2202 NULL, NULL, block_start, &hook_start);
308711e5 2203 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 2204 NULL, NULL, block_end, &hook_end);
308711e5 2205
eed2ef37 2206 nb_tracefile = ts->parent.tracefiles->len;
308711e5 2207
dbb7bb09 2208 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2209 tfs =
2210 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2211 LttvTracefileContext, j));
a5ba1787 2212 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 2213 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 2214 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 2215 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2216 }
2217 }
2218}
2219#endif //0
2220
2221void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2222{
2223 LttvTraceset *traceset = self->parent.ts;
2224
2225 guint i, j, nb_trace, nb_tracefile;
2226
2227 LttvTraceState *ts;
2228
2229 LttvTracefileState *tfs;
2230
2231
2232 nb_trace = lttv_traceset_number(traceset);
2233 for(i = 0 ; i < nb_trace ; i++) {
2234
2235 ts = (LttvTraceState *)self->parent.traces[i];
2236 nb_tracefile = ts->parent.tracefiles->len;
2237
3054461a 2238 guint *event_count = g_new(guint, 1);
2239 *event_count = 0;
2240
eed2ef37 2241 for(j = 0 ; j < nb_tracefile ; j++) {
2242 tfs =
cb03932a 2243 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2244 LttvTracefileContext*, j));
eed2ef37 2245 lttv_hooks_add(tfs->parent.event,
2246 state_save_event_hook,
2247 event_count,
2248 LTTV_PRIO_STATE);
2249
308711e5 2250 }
2251 }
14aecf75 2252
2253 lttv_process_traceset_begin(&self->parent,
2254 NULL, NULL, NULL, NULL, NULL);
2255
308711e5 2256}
2257
b56b5fec 2258gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2259{
2260 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2261
2262 lttv_state_save_add_event_hooks(tss);
2263
2264 return 0;
2265}
2266
308711e5 2267
eed2ef37 2268#if 0
308711e5 2269void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2270{
2271 LttvTraceset *traceset = self->parent.ts;
2272
00e74b69 2273 guint i, j, nb_trace, nb_tracefile;
308711e5 2274
2275 LttvTraceState *ts;
2276
2277 LttvTracefileState *tfs;
2278
08b1c66e 2279 LttvTraceHook hook_start, hook_end;
308711e5 2280
2281 nb_trace = lttv_traceset_number(traceset);
2282 for(i = 0 ; i < nb_trace ; i++) {
2283 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 2284
08b1c66e 2285 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2286 NULL, NULL, block_start, &hook_start);
2287
308711e5 2288 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 2289 NULL, NULL, block_end, &hook_end);
308711e5 2290
eed2ef37 2291 nb_tracefile = ts->parent.tracefiles->len;
308711e5 2292
dbb7bb09 2293 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2294 tfs =
2295 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2296 LttvTracefileContext, j));
308711e5 2297 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 2298 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 2299 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 2300 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 2301 }
2302 }
2303}
eed2ef37 2304#endif //0
2305
2306void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2307{
2308 LttvTraceset *traceset = self->parent.ts;
2309
2310 guint i, j, nb_trace, nb_tracefile;
2311
2312 LttvTraceState *ts;
2313
2314 LttvTracefileState *tfs;
2315
14aecf75 2316 LttvHooks *after_trace = lttv_hooks_new();
2317
2318 lttv_hooks_add(after_trace,
2319 state_save_after_trace_hook,
2320 NULL,
2321 LTTV_PRIO_STATE);
2322
2323
2324 lttv_process_traceset_end(&self->parent,
2325 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 2326
14aecf75 2327 lttv_hooks_destroy(after_trace);
2328
eed2ef37 2329 nb_trace = lttv_traceset_number(traceset);
2330 for(i = 0 ; i < nb_trace ; i++) {
2331
2332 ts = (LttvTraceState *)self->parent.traces[i];
2333 nb_tracefile = ts->parent.tracefiles->len;
2334
22b165e9 2335 guint *event_count = NULL;
eed2ef37 2336
2337 for(j = 0 ; j < nb_tracefile ; j++) {
2338 tfs =
cb03932a 2339 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2340 LttvTracefileContext*, j));
eed2ef37 2341 event_count = lttv_hooks_remove(tfs->parent.event,
2342 state_save_event_hook);
eed2ef37 2343 }
22b165e9 2344 if(event_count) g_free(event_count);
eed2ef37 2345 }
2346}
308711e5 2347
b56b5fec 2348gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2349{
2350 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2351
2352 lttv_state_save_remove_event_hooks(tss);
2353
2354 return 0;
2355}
308711e5 2356
dd025f91 2357void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 2358{
2359 LttvTraceset *traceset = self->parent.ts;
2360
00e74b69 2361 guint i, nb_trace;
308711e5 2362
2363 int min_pos, mid_pos, max_pos;
2364
728d0c3e 2365 guint call_rest = 0;
2366
308711e5 2367 LttvTraceState *tcs;
2368
2369 LttvAttributeValue value;
2370
2371 LttvAttributeType type;
2372
2373 LttvAttributeName name;
2374
2375 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2376
d448fce2 2377 //g_tree_destroy(self->parent.pqueue);
2378 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 2379
728d0c3e 2380 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2381
308711e5 2382 nb_trace = lttv_traceset_number(traceset);
2383 for(i = 0 ; i < nb_trace ; i++) {
2384 tcs = (LttvTraceState *)self->parent.traces[i];
2385
2a2fa4f0 2386 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2387 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2388 LTTV_STATE_SAVED_STATES);
2389 min_pos = -1;
2390
2391 if(saved_states_tree) {
dd025f91 2392 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2393 mid_pos = max_pos / 2;
2394 while(min_pos < max_pos) {
2395 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
2396 g_assert(type == LTTV_GOBJECT);
2397 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2398 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2399 &value);
2400 g_assert(type == LTTV_TIME);
2401 if(ltt_time_compare(*(value.v_time), t) < 0) {
2402 min_pos = mid_pos;
2403 closest_tree = saved_state_tree;
2404 }
2405 else max_pos = mid_pos - 1;
2406
2407 mid_pos = (min_pos + max_pos + 1) / 2;
2408 }
2a2fa4f0 2409 }
dd025f91 2410
2a2fa4f0 2411 /* restore the closest earlier saved state */
f95bc830 2412 if(min_pos != -1) {
2413 lttv_state_restore(tcs, closest_tree);
728d0c3e 2414 call_rest = 1;
f95bc830 2415 }
dd025f91 2416
2a2fa4f0 2417 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 2418 else {
2419 restore_init_state(tcs);
2420 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 2421 }
9444deae 2422 }
dd025f91 2423 /* We want to seek quickly without restoring/updating the state */
2424 else {
308711e5 2425 restore_init_state(tcs);
dd025f91 2426 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 2427 }
308711e5 2428 }
728d0c3e 2429 if(!call_rest) g_info("NOT Calling restore");
308711e5 2430}
2431
2432
2433static void
2434traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2435{
2436}
2437
2438
2439static void
2440traceset_state_finalize (LttvTracesetState *self)
2441{
2442 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2443 finalize(G_OBJECT(self));
2444}
2445
2446
2447static void
2448traceset_state_class_init (LttvTracesetContextClass *klass)
2449{
2450 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2451
2452 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2453 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2454 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2455 klass->new_traceset_context = new_traceset_context;
2456 klass->new_trace_context = new_trace_context;
2457 klass->new_tracefile_context = new_tracefile_context;
2458}
2459
2460
2461GType
2462lttv_traceset_state_get_type(void)
2463{
2464 static GType type = 0;
2465 if (type == 0) {
2466 static const GTypeInfo info = {
2467 sizeof (LttvTracesetStateClass),
2468 NULL, /* base_init */
2469 NULL, /* base_finalize */
2470 (GClassInitFunc) traceset_state_class_init, /* class_init */
2471 NULL, /* class_finalize */
2472 NULL, /* class_data */
dbb7bb09 2473 sizeof (LttvTracesetState),
308711e5 2474 0, /* n_preallocs */
00e74b69 2475 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2476 NULL /* value handling */
308711e5 2477 };
2478
2479 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2480 &info, 0);
2481 }
2482 return type;
2483}
2484
2485
2486static void
2487trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2488{
2489}
2490
2491
2492static void
2493trace_state_finalize (LttvTraceState *self)
2494{
2495 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2496 finalize(G_OBJECT(self));
2497}
2498
2499
2500static void
2501trace_state_class_init (LttvTraceStateClass *klass)
2502{
2503 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2504
2505 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2506 klass->state_save = state_save;
2507 klass->state_restore = state_restore;
2508 klass->state_saved_free = state_saved_free;
2509}
2510
2511
2512GType
2513lttv_trace_state_get_type(void)
2514{
2515 static GType type = 0;
2516 if (type == 0) {
2517 static const GTypeInfo info = {
2518 sizeof (LttvTraceStateClass),
2519 NULL, /* base_init */
2520 NULL, /* base_finalize */
2521 (GClassInitFunc) trace_state_class_init, /* class_init */
2522 NULL, /* class_finalize */
2523 NULL, /* class_data */
2524 sizeof (LttvTraceState),
2525 0, /* n_preallocs */
00e74b69 2526 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2527 NULL /* value handling */
308711e5 2528 };
2529
2530 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2531 "LttvTraceStateType", &info, 0);
2532 }
2533 return type;
2534}
2535
2536
2537static void
2538tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2539{
2540}
2541
2542
2543static void
2544tracefile_state_finalize (LttvTracefileState *self)
2545{
2546 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2547 finalize(G_OBJECT(self));
2548}
2549
2550
2551static void
2552tracefile_state_class_init (LttvTracefileStateClass *klass)
2553{
2554 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2555
2556 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2557}
2558
2559
2560GType
2561lttv_tracefile_state_get_type(void)
2562{
2563 static GType type = 0;
2564 if (type == 0) {
2565 static const GTypeInfo info = {
2566 sizeof (LttvTracefileStateClass),
2567 NULL, /* base_init */
2568 NULL, /* base_finalize */
2569 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2570 NULL, /* class_finalize */
2571 NULL, /* class_data */
2572 sizeof (LttvTracefileState),
2573 0, /* n_preallocs */
00e74b69 2574 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2575 NULL /* value handling */
308711e5 2576 };
2577
2578 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2579 "LttvTracefileStateType", &info, 0);
2580 }
2581 return type;
2582}
2583
2584
08b1c66e 2585static void module_init()
ffd54a90 2586{
2587 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b3fd4c02 2588 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2589 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2590 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2591 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2592 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2593 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2594 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2595 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2596 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2597 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2598 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2599 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2600 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2601 LTTV_STATE_RUN = g_quark_from_string("RUN");
2602 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
308711e5 2603 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2604 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2605 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 2606 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 2607 LTTV_STATE_EVENT = g_quark_from_string("event");
2608 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 2609 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 2610 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 2611 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 2612 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2613 LTTV_STATE_TRACE_STATE_USE_COUNT =
2614 g_quark_from_string("trace_state_use_count");
eed2ef37 2615
2616
2617 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 2618 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
eed2ef37 2619 LTT_FACILITY_PROCESS = g_quark_from_string("process");
f4b88a7d 2620 LTT_FACILITY_FS = g_quark_from_string("fs");
b3fd4c02 2621 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
302efbad 2622 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
eed2ef37 2623
2624
2625 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2626 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2627 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2628 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2629 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2630 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
faf074a3 2631 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2632 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
eed2ef37 2633 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2634 LTT_EVENT_FORK = g_quark_from_string("fork");
7bfd7820 2635 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
eed2ef37 2636 LTT_EVENT_EXIT = g_quark_from_string("exit");
2637 LTT_EVENT_FREE = g_quark_from_string("free");
f4b88a7d 2638 LTT_EVENT_EXEC = g_quark_from_string("exec");
b3fd4c02 2639 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
302efbad 2640 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2641 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
eed2ef37 2642
2643
2644 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2645 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2646 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 2647 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
eed2ef37 2648 LTT_FIELD_OUT = g_quark_from_string("out");
2649 LTT_FIELD_IN = g_quark_from_string("in");
2650 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2651 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2652 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2653 LTT_FIELD_PID = g_quark_from_string("pid");
f4b88a7d 2654 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 2655 LTT_FIELD_NAME = g_quark_from_string("name");
2656 LTT_FIELD_MODE = g_quark_from_string("mode");
2657 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2658 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 2659 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2660 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
eed2ef37 2661
ffd54a90 2662}
dc877563 2663
08b1c66e 2664static void module_destroy()
ffd54a90 2665{
2666}
dc877563 2667
2668
08b1c66e 2669LTTV_MODULE("state", "State computation", \
2670 "Update the system state, possibly saving it at intervals", \
2671 module_init, module_destroy)
2672
dc877563 2673
2674
This page took 0.175723 seconds and 4 git commands to generate.