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