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