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