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