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