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