start adding IRQ mode for cpu resource
[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
7df20ca4 33/* Comment :
34 * Mathieu Desnoyers
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
38 *
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
41 */
42
e8f2280c 43#define PREALLOCATED_EXECUTION_STACK 10
44
eed2ef37 45/* Facilities Quarks */
46
47GQuark
48 LTT_FACILITY_KERNEL,
f5d7967f 49 LTT_FACILITY_KERNEL_ARCH,
86c32a8f 50 LTT_FACILITY_LIST,
b3fd4c02 51 LTT_FACILITY_FS,
80e0221b 52 LTT_FACILITY_USER_GENERIC;
eed2ef37 53
54/* Events Quarks */
55
56GQuark
57 LTT_EVENT_SYSCALL_ENTRY,
58 LTT_EVENT_SYSCALL_EXIT,
59 LTT_EVENT_TRAP_ENTRY,
60 LTT_EVENT_TRAP_EXIT,
61 LTT_EVENT_IRQ_ENTRY,
62 LTT_EVENT_IRQ_EXIT,
faf074a3 63 LTT_EVENT_SOFT_IRQ_ENTRY,
64 LTT_EVENT_SOFT_IRQ_EXIT,
86c32a8f 65 LTT_EVENT_SCHED_SCHEDULE,
66 LTT_EVENT_PROCESS_FORK,
67 LTT_EVENT_KTHREAD_CREATE,
68 LTT_EVENT_PROCESS_EXIT,
69 LTT_EVENT_PROCESS_FREE,
b3fd4c02 70 LTT_EVENT_EXEC,
86c32a8f 71 LTT_EVENT_PROCESS_STATE,
c3b3b60b 72 LTT_EVENT_STATEDUMP_END,
80e0221b 73 LTT_EVENT_FUNCTION_ENTRY,
74 LTT_EVENT_FUNCTION_EXIT,
75 LTT_EVENT_THREAD_BRAND;
eed2ef37 76
77/* Fields Quarks */
78
79GQuark
80 LTT_FIELD_SYSCALL_ID,
81 LTT_FIELD_TRAP_ID,
82 LTT_FIELD_IRQ_ID,
faf074a3 83 LTT_FIELD_SOFT_IRQ_ID,
f63ebe51 84 LTT_FIELD_PREV_PID,
85 LTT_FIELD_NEXT_PID,
86 LTT_FIELD_PREV_STATE,
eed2ef37 87 LTT_FIELD_PARENT_PID,
88 LTT_FIELD_CHILD_PID,
f4b88a7d 89 LTT_FIELD_PID,
fcc08e1e 90 LTT_FIELD_TGID,
f63ebe51 91 LTT_FIELD_CHILD_TGID,
b3fd4c02 92 LTT_FIELD_FILENAME,
93 LTT_FIELD_NAME,
e62e7f3a 94 LTT_FIELD_TYPE,
b3fd4c02 95 LTT_FIELD_MODE,
96 LTT_FIELD_SUBMODE,
302efbad 97 LTT_FIELD_STATUS,
80e0221b 98 LTT_FIELD_THIS_FN,
99 LTT_FIELD_CALL_SITE;
eed2ef37 100
b445142a 101LttvExecutionMode
102 LTTV_STATE_MODE_UNKNOWN,
ffd54a90 103 LTTV_STATE_USER_MODE,
104 LTTV_STATE_SYSCALL,
105 LTTV_STATE_TRAP,
faf074a3 106 LTTV_STATE_IRQ,
107 LTTV_STATE_SOFT_IRQ;
ffd54a90 108
b445142a 109LttvExecutionSubmode
110 LTTV_STATE_SUBMODE_UNKNOWN,
111 LTTV_STATE_SUBMODE_NONE;
ffd54a90 112
113LttvProcessStatus
114 LTTV_STATE_UNNAMED,
115 LTTV_STATE_WAIT_FORK,
116 LTTV_STATE_WAIT_CPU,
dbd243b1 117 LTTV_STATE_EXIT,
0828099d 118 LTTV_STATE_ZOMBIE,
ffd54a90 119 LTTV_STATE_WAIT,
791dffa6 120 LTTV_STATE_RUN,
121 LTTV_STATE_DEAD;
ffd54a90 122
c4a72569 123GQuark
124 LTTV_STATE_UNBRANDED;
125
e62e7f3a 126LttvProcessType
127 LTTV_STATE_USER_THREAD,
80e0221b 128 LTTV_STATE_KERNEL_THREAD;
e62e7f3a 129
44ffb95f 130LttvCPUMode
131 LTTV_CPU_UNKNOWN,
132 LTTV_CPU_IDLE,
598026ba 133 LTTV_CPU_BUSY,
134 LTTV_CPU_IRQ;
44ffb95f 135
ba576a78 136static GQuark
308711e5 137 LTTV_STATE_TRACEFILES,
138 LTTV_STATE_PROCESSES,
139 LTTV_STATE_PROCESS,
348c6ba8 140 LTTV_STATE_RUNNING_PROCESS,
308711e5 141 LTTV_STATE_EVENT,
142 LTTV_STATE_SAVED_STATES,
dbb7bb09 143 LTTV_STATE_SAVED_STATES_TIME,
308711e5 144 LTTV_STATE_TIME,
f95bc830 145 LTTV_STATE_HOOKS,
146 LTTV_STATE_NAME_TABLES,
147 LTTV_STATE_TRACE_STATE_USE_COUNT;
ba576a78 148
f95bc830 149static void create_max_time(LttvTraceState *tcs);
150
151static void get_max_time(LttvTraceState *tcs);
152
153static void free_max_time(LttvTraceState *tcs);
154
155static void create_name_tables(LttvTraceState *tcs);
156
157static void get_name_tables(LttvTraceState *tcs);
b445142a 158
159static void free_name_tables(LttvTraceState *tcs);
160
f95bc830 161static void free_saved_state(LttvTraceState *tcs);
162
308711e5 163static void lttv_state_free_process_table(GHashTable *processes);
ba576a78 164
7df20ca4 165static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
166 GPtrArray *quarktable);
dc877563 167
308711e5 168void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
169{
170 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
171}
172
173
174void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
175{
176 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
177}
178
179
2d262115 180void lttv_state_state_saved_free(LttvTraceState *self,
308711e5 181 LttvAttribute *container)
182{
f95bc830 183 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
308711e5 184}
185
186
2a2fa4f0 187guint process_hash(gconstpointer key)
188{
7893f726 189 guint pid = ((const LttvProcessState *)key)->pid;
190 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
2a2fa4f0 191}
192
193
1d1df11d 194/* If the hash table hash function is well distributed,
195 * the process_equal should compare different pid */
2a2fa4f0 196gboolean process_equal(gconstpointer a, gconstpointer b)
197{
00e74b69 198 const LttvProcessState *process_a, *process_b;
1d1df11d 199 gboolean ret = TRUE;
200
00e74b69 201 process_a = (const LttvProcessState *)a;
202 process_b = (const LttvProcessState *)b;
1d1df11d 203
204 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
205 else if(likely(process_a->pid == 0 &&
348c6ba8 206 process_a->cpu != process_b->cpu)) ret = FALSE;
2a2fa4f0 207
1d1df11d 208 return ret;
2a2fa4f0 209}
210
6806b3c6 211static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
212{
80e0221b 213 g_tree_destroy((GTree*)value);
6806b3c6 214}
215
216static void lttv_state_free_usertraces(GHashTable *usertraces)
217{
80e0221b 218 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
219 g_hash_table_destroy(usertraces);
6806b3c6 220}
221
222
2a2fa4f0 223
308711e5 224static void
225restore_init_state(LttvTraceState *self)
226{
348c6ba8 227 guint i, nb_cpus;
308711e5 228
229 LttvTracefileState *tfcs;
954417fa 230
231 LttTime start_time, end_time;
308711e5 232
348c6ba8 233 /* Free the process tables */
308711e5 234 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
80e0221b 235 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
2a2fa4f0 236 self->processes = g_hash_table_new(process_hash, process_equal);
80e0221b 237 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
308711e5 238 self->nb_event = 0;
239
348c6ba8 240 /* Seek time to beginning */
9ba3aaaf 241 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
242 // closest. It's the tracecontext job to seek the trace to the beginning
243 // anyway : the init state might be used at the middle of the trace as well...
244 //g_tree_destroy(self->parent.ts_context->pqueue);
245 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
348c6ba8 246
954417fa 247 ltt_trace_time_span_get(self->parent.t, &start_time, &end_time);
9ba3aaaf 248
249 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
348c6ba8 250
251 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
252
253 /* Put the per cpu running_process to beginning state : process 0. */
254 for(i=0; i< nb_cpus; i++) {
1e304fa1 255 LttvExecutionState *es;
fcc08e1e 256 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
954417fa 257 LTTV_STATE_UNNAMED, &start_time);
1e304fa1 258 /* We are not sure is it's a kernel thread or normal thread, put the
259 * bottom stack state to unknown */
260 self->running_process[i]->execution_stack =
261 g_array_set_size(self->running_process[i]->execution_stack, 1);
262 es = self->running_process[i]->state =
263 &g_array_index(self->running_process[i]->execution_stack,
264 LttvExecutionState, 0);
265 es->t = LTTV_STATE_MODE_UNKNOWN;
c4a72569 266 es->s = LTTV_STATE_UNNAMED;
1e304fa1 267
c4a72569 268 //self->running_process[i]->state->s = LTTV_STATE_RUN;
348c6ba8 269 self->running_process[i]->cpu = i;
270 }
271
272#if 0
eed2ef37 273 nb_tracefile = self->parent.tracefiles->len;
308711e5 274
dbb7bb09 275 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 276 tfcs =
cb03932a 277 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
278 LttvTracefileContext*, i));
d3e01c7a 279 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
eed2ef37 280// tfcs->saved_position = 0;
2a2fa4f0 281 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
282 tfcs->process->state->s = LTTV_STATE_RUN;
283 tfcs->process->last_cpu = tfcs->cpu_name;
2c82c4dc 284 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
308711e5 285 }
348c6ba8 286#endif //0
308711e5 287}
288
348c6ba8 289//static LttTime time_zero = {0,0};
308711e5 290
6806b3c6 291static gint compare_usertraces(gconstpointer a, gconstpointer b,
80e0221b 292 gpointer user_data)
6806b3c6 293{
80e0221b 294 const LttTime *t1 = (const LttTime *)a;
295 const LttTime *t2 = (const LttTime *)b;
6806b3c6 296
80e0221b 297 return ltt_time_compare(*t1, *t2);
6806b3c6 298}
299
300static void free_usertrace_key(gpointer data)
301{
80e0221b 302 g_free(data);
6806b3c6 303}
304
7df20ca4 305#define MAX_STRING_LEN 4096
306
307static void
308state_load_saved_states(LttvTraceState *tcs)
309{
310 FILE *fp;
311 GPtrArray *quarktable;
312 char *trace_path;
313 char path[PATH_MAX];
314 guint count;
315 guint i;
316 tcs->has_precomputed_states = FALSE;
317 GQuark q;
318 gchar *string;
319 gint hdr;
320 gchar buf[MAX_STRING_LEN];
321 guint len;
322
323 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
324 strncpy(path, trace_path, PATH_MAX-1);
325 count = strnlen(trace_path, PATH_MAX-1);
326 // quarktable : open, test
327 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
328 fp = fopen(path, "r");
329 if(!fp) return;
330 quarktable = g_ptr_array_sized_new(4096);
331
332 /* Index 0 is null */
333 hdr = fgetc(fp);
334 if(hdr == EOF) return;
335 g_assert(hdr == HDR_QUARKS);
336 q = 1;
337 do {
338 hdr = fgetc(fp);
339 if(hdr == EOF) break;
340 g_assert(hdr == HDR_QUARK);
341 g_ptr_array_set_size(quarktable, q+1);
342 i=0;
343 while(1) {
344 fread(&buf[i], sizeof(gchar), 1, fp);
345 if(buf[i] == '\0' || feof(fp)) break;
346 i++;
347 }
348 len = strnlen(buf, MAX_STRING_LEN-1);
349 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
350 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
351 q++;
352 } while(1);
353
354 fclose(fp);
ce05e187 355
7df20ca4 356 // saved_states : open, test
357 strncpy(path, trace_path, PATH_MAX-1);
358 count = strnlen(trace_path, PATH_MAX-1);
359 strncat(path, "/precomputed/states", PATH_MAX-count-1);
360 fp = fopen(path, "r");
361 if(!fp) return;
362
363 hdr = fgetc(fp);
364 if(hdr != HDR_TRACE) goto end;
365
366 lttv_trace_states_read_raw(tcs, fp, quarktable);
367
368 tcs->has_precomputed_states = TRUE;
369
370end:
371 fclose(fp);
372
373 /* Free the quarktable */
374 for(i=0; i<quarktable->len; i++) {
375 string = g_ptr_array_index (quarktable, i);
376 g_free(string);
377 }
378 g_ptr_array_free(quarktable, TRUE);
379 return;
380}
381
dc877563 382static void
383init(LttvTracesetState *self, LttvTraceset *ts)
384{
dbb7bb09 385 guint i, j, nb_trace, nb_tracefile;
dc877563 386
ffd54a90 387 LttvTraceContext *tc;
dc877563 388
ffd54a90 389 LttvTraceState *tcs;
390
ffd54a90 391 LttvTracefileState *tfcs;
3d27549e 392
dbb7bb09 393 LttvAttributeValue v;
394
b445142a 395 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
396 init((LttvTracesetContext *)self, ts);
dc877563 397
398 nb_trace = lttv_traceset_number(ts);
399 for(i = 0 ; i < nb_trace ; i++) {
b445142a 400 tc = self->parent.traces[i];
021eeb41 401 tcs = LTTV_TRACE_STATE(tc);
eed2ef37 402 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
f95bc830 403 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
404 LTTV_UINT, &v);
405 (*v.v_uint)++;
dbb7bb09 406
f95bc830 407 if(*(v.v_uint) == 1) {
408 create_name_tables(tcs);
409 create_max_time(tcs);
410 }
411 get_name_tables(tcs);
412 get_max_time(tcs);
dc877563 413
eed2ef37 414 nb_tracefile = tc->tracefiles->len;
ae3d0f50 415 tcs->processes = NULL;
6806b3c6 416 tcs->usertraces = NULL;
ae3d0f50 417 tcs->running_process = g_new(LttvProcessState*,
418 ltt_trace_get_num_cpu(tc->t));
44ffb95f 419 tcs->cpu_states = g_new(LttvCPUState,
420 ltt_trace_get_num_cpu(tc->t));
ae3d0f50 421 restore_init_state(tcs);
dc877563 422 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 423 tfcs =
cb03932a 424 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
425 LttvTracefileContext*, j));
348c6ba8 426 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
80e0221b 427 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
44ffb95f 428 tfcs->cpu_state = &(tcs->cpu_states[tfcs->cpu]);
80e0221b 429 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
430 /* It's a Usertrace */
431 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
432 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
433 (gconstpointer)tid);
434 if(!usertrace_tree) {
435 usertrace_tree = g_tree_new_full(compare_usertraces,
436 NULL, free_usertrace_key, NULL);
437 g_hash_table_insert(tcs->usertraces,
438 (gpointer)tid, usertrace_tree);
439 }
440 LttTime *timestamp = g_new(LttTime, 1);
441 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
442 ltt_tracefile_creation(tfcs->parent.tf));
443 g_tree_insert(usertrace_tree, timestamp, tfcs);
444 }
6806b3c6 445 }
446
7df20ca4 447 /* See if the trace has saved states */
448 state_load_saved_states(tcs);
dc877563 449 }
450}
451
dc877563 452static void
453fini(LttvTracesetState *self)
454{
00e74b69 455 guint i, nb_trace;
dc877563 456
ffd54a90 457 LttvTraceState *tcs;
dc877563 458
ffd54a90 459 LttvTracefileState *tfcs;
dc877563 460
f95bc830 461 LttvAttributeValue v;
462
ffd54a90 463 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
dc877563 464 for(i = 0 ; i < nb_trace ; i++) {
ffd54a90 465 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
f95bc830 466 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
467 LTTV_UINT, &v);
00e74b69 468
469 g_assert(*(v.v_uint) != 0);
f95bc830 470 (*v.v_uint)--;
471
f95bc830 472 if(*(v.v_uint) == 0) {
473 free_name_tables(tcs);
474 free_max_time(tcs);
475 free_saved_state(tcs);
476 }
348c6ba8 477 g_free(tcs->running_process);
478 tcs->running_process = NULL;
308711e5 479 lttv_state_free_process_table(tcs->processes);
80e0221b 480 lttv_state_free_usertraces(tcs->usertraces);
308711e5 481 tcs->processes = NULL;
6806b3c6 482 tcs->usertraces = NULL;
dc877563 483 }
b445142a 484 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
485 fini((LttvTracesetContext *)self);
dc877563 486}
487
488
c432246e 489static LttvTracesetContext *
dc877563 490new_traceset_context(LttvTracesetContext *self)
491{
ffd54a90 492 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
dc877563 493}
494
495
c432246e 496static LttvTraceContext *
dc877563 497new_trace_context(LttvTracesetContext *self)
498{
ffd54a90 499 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
dc877563 500}
501
502
c432246e 503static LttvTracefileContext *
dc877563 504new_tracefile_context(LttvTracesetContext *self)
505{
ffd54a90 506 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
507}
508
509
dbb7bb09 510/* Write the process state of the trace */
511
512static void write_process_state(gpointer key, gpointer value,
513 gpointer user_data)
514{
515 LttvProcessState *process;
516
517 LttvExecutionState *es;
518
519 FILE *fp = (FILE *)user_data;
520
521 guint i;
d4dd4885 522 guint64 address;
dbb7bb09 523
524 process = (LttvProcessState *)value;
525 fprintf(fp,
d41c66bf 526" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
d4dd4885 527 process, process->pid, process->tgid, process->ppid,
528 g_quark_to_string(process->type),
80e0221b 529 process->creation_time.tv_sec,
d4dd4885 530 process->creation_time.tv_nsec,
531 process->insertion_time.tv_sec,
532 process->insertion_time.tv_nsec,
533 g_quark_to_string(process->name),
7b5f6cf1 534 g_quark_to_string(process->brand),
6d0cdf22 535 process->cpu);
dbb7bb09 536
537 for(i = 0 ; i < process->execution_stack->len; i++) {
538 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
539 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
80e0221b 540 g_quark_to_string(es->t), g_quark_to_string(es->n),
dbb7bb09 541 es->entry.tv_sec, es->entry.tv_nsec);
542 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
543 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
544 }
d4dd4885 545
6d0cdf22 546 for(i = 0 ; i < process->user_stack->len; i++) {
d4dd4885 547 address = &g_array_index(process->user_stack, guint64, i);
548 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
549 address);
550 }
551
552 if(process->usertrace) {
553 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
6d0cdf22 554 g_quark_to_string(process->usertrace->tracefile_name),
d4dd4885 555 process->usertrace->cpu);
556 }
557
558
dbb7bb09 559 fprintf(fp, " </PROCESS>\n");
560}
561
562
563void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
564{
eed2ef37 565 guint i, nb_tracefile, nb_block, offset;
566 guint64 tsc;
dbb7bb09 567
568 LttvTracefileState *tfcs;
569
570 LttTracefile *tf;
571
572 LttEventPosition *ep;
573
348c6ba8 574 guint nb_cpus;
575
dbb7bb09 576 ep = ltt_event_position_new();
577
578 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
579
580 g_hash_table_foreach(self->processes, write_process_state, fp);
348c6ba8 581
582 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
583 for(i=0;i<nb_cpus;i++) {
6d0cdf22 584 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
348c6ba8 585 i, self->running_process[i]->pid);
586 }
dbb7bb09 587
eed2ef37 588 nb_tracefile = self->parent.tracefiles->len;
dbb7bb09 589
590 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 591 tfcs =
cb03932a 592 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
593 LttvTracefileContext*, i));
348c6ba8 594 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
595 tfcs->parent.timestamp.tv_sec,
08b1c66e 596 tfcs->parent.timestamp.tv_nsec);
eed2ef37 597 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
598 if(e == NULL) fprintf(fp,"/>\n");
dbb7bb09 599 else {
eed2ef37 600 ltt_event_position(e, ep);
601 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
27304273 602 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
eed2ef37 603 tsc);
dbb7bb09 604 }
605 }
606 g_free(ep);
6d0cdf22 607 fprintf(fp,"</PROCESS_STATE>\n");
608}
609
610
611static void write_process_state_raw(gpointer key, gpointer value,
612 gpointer user_data)
613{
614 LttvProcessState *process;
615
616 LttvExecutionState *es;
617
618 FILE *fp = (FILE *)user_data;
619
620 guint i;
621 guint64 address;
622
623 process = (LttvProcessState *)value;
624 fputc(HDR_PROCESS, fp);
625 //fwrite(&header, sizeof(header), 1, fp);
626 //fprintf(fp, "%s", g_quark_to_string(process->type));
627 //fputc('\0', fp);
628 fwrite(&process->type, sizeof(process->type), 1, fp);
629 //fprintf(fp, "%s", g_quark_to_string(process->name));
630 //fputc('\0', fp);
631 fwrite(&process->name, sizeof(process->name), 1, fp);
632 //fprintf(fp, "%s", g_quark_to_string(process->brand));
633 //fputc('\0', fp);
634 fwrite(&process->brand, sizeof(process->brand), 1, fp);
635 fwrite(&process->pid, sizeof(process->pid), 1, fp);
636 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
637 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
638 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
639 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
640 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
641
642#if 0
643 fprintf(fp,
644" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
645 process, process->pid, process->tgid, process->ppid,
646 g_quark_to_string(process->type),
647 process->creation_time.tv_sec,
648 process->creation_time.tv_nsec,
649 process->insertion_time.tv_sec,
650 process->insertion_time.tv_nsec,
651 g_quark_to_string(process->name),
652 g_quark_to_string(process->brand),
653 process->cpu);
654#endif //0
655
656 for(i = 0 ; i < process->execution_stack->len; i++) {
657 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
658
659 fputc(HDR_ES, fp);
660 //fprintf(fp, "%s", g_quark_to_string(es->t));
661 //fputc('\0', fp);
662 fwrite(&es->t, sizeof(es->t), 1, fp);
663 //fprintf(fp, "%s", g_quark_to_string(es->n));
664 //fputc('\0', fp);
665 fwrite(&es->n, sizeof(es->n), 1, fp);
666 //fprintf(fp, "%s", g_quark_to_string(es->s));
667 //fputc('\0', fp);
668 fwrite(&es->s, sizeof(es->s), 1, fp);
669 fwrite(&es->entry, sizeof(es->entry), 1, fp);
670 fwrite(&es->change, sizeof(es->change), 1, fp);
7df20ca4 671 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
6d0cdf22 672#if 0
673 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
674 g_quark_to_string(es->t), g_quark_to_string(es->n),
675 es->entry.tv_sec, es->entry.tv_nsec);
676 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
677 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
678#endif //0
679 }
680
681 for(i = 0 ; i < process->user_stack->len; i++) {
682 address = &g_array_index(process->user_stack, guint64, i);
683 fputc(HDR_USER_STACK, fp);
684 fwrite(&address, sizeof(address), 1, fp);
685#if 0
686 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
687 address);
688#endif //0
689 }
690
691 if(process->usertrace) {
692 fputc(HDR_USERTRACE, fp);
693 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
694 //fputc('\0', fp);
695 fwrite(&process->usertrace->tracefile_name,
696 sizeof(process->usertrace->tracefile_name), 1, fp);
697 fwrite(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
698#if 0
699 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
700 g_quark_to_string(process->usertrace->tracefile_name),
701 process->usertrace->cpu);
702#endif //0
703 }
704
dbb7bb09 705}
706
707
6d0cdf22 708void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
709{
710 guint i, nb_tracefile, nb_block, offset;
711 guint64 tsc;
712
713 LttvTracefileState *tfcs;
714
715 LttTracefile *tf;
716
717 LttEventPosition *ep;
718
719 guint nb_cpus;
720
721 ep = ltt_event_position_new();
722
723 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
724 fputc(HDR_PROCESS_STATE, fp);
725 fwrite(&t, sizeof(t), 1, fp);
726
727 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
728
729 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
730 for(i=0;i<nb_cpus;i++) {
731 fputc(HDR_CPU, fp);
732 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
733 fwrite(&self->running_process[i]->pid,
734 sizeof(self->running_process[i]->pid), 1, fp);
735 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
736 // i, self->running_process[i]->pid);
737 }
738
739 nb_tracefile = self->parent.tracefiles->len;
740
741 for(i = 0 ; i < nb_tracefile ; i++) {
742 tfcs =
743 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
744 LttvTracefileContext*, i));
745 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
746 // tfcs->parent.timestamp.tv_sec,
747 // tfcs->parent.timestamp.tv_nsec);
748 fputc(HDR_TRACEFILE, fp);
749 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
750 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
751 * position following : end of trace */
752 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
753 if(e != NULL) {
754 ltt_event_position(e, ep);
755 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
756 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
757 // tsc);
758 fwrite(&nb_block, sizeof(nb_block), 1, fp);
759 fwrite(&offset, sizeof(offset), 1, fp);
760 fwrite(&tsc, sizeof(tsc), 1, fp);
761 }
762 }
763 g_free(ep);
764}
765
766
767/* Read process state from a file */
768
769/* Called because a HDR_PROCESS was found */
7df20ca4 770static void read_process_state_raw(LttvTraceState *self, FILE *fp,
771 GPtrArray *quarktable)
6d0cdf22 772{
773 LttvExecutionState *es;
774 LttvProcessState *process, *parent_process;
775 LttvProcessState tmp;
7df20ca4 776 GQuark tmpq;
6d0cdf22 777
6d0cdf22 778 guint i;
7df20ca4 779 guint64 *address;
6d0cdf22 780 guint cpu;
781
7df20ca4 782 /* TODO : check return value */
6d0cdf22 783 fread(&tmp.type, sizeof(tmp.type), 1, fp);
784 fread(&tmp.name, sizeof(tmp.name), 1, fp);
785 fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
786 fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
787 fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
788 fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
789 fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
790 fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
791 fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
792
793 if(tmp.pid == 0) {
d41c66bf 794 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
6d0cdf22 795 } else {
796 /* We must link to the parent */
797 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
d41c66bf 798 &ltt_time_zero);
ce05e187 799 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
800 if(process == NULL) {
801 process = lttv_state_create_process(self, parent_process, tmp.cpu,
802 tmp.pid, tmp.tgid,
803 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
804 &tmp.creation_time);
805 }
6d0cdf22 806 }
7df20ca4 807 process->insertion_time = tmp.insertion_time;
6d0cdf22 808 process->creation_time = tmp.creation_time;
7df20ca4 809 process->type = g_quark_from_string(
810 (gchar*)g_ptr_array_index(quarktable, tmp.type));
6d0cdf22 811 process->tgid = tmp.tgid;
7df20ca4 812 process->ppid = tmp.ppid;
813 process->brand = g_quark_from_string(
814 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
815 process->name =
816 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
6d0cdf22 817
ce05e187 818
6d0cdf22 819 do {
820 if(feof(fp) || ferror(fp)) goto end_loop;
821
d41c66bf 822 gint hdr = fgetc(fp);
7df20ca4 823 if(hdr == EOF) goto end_loop;
6d0cdf22 824
825 switch(hdr) {
826 case HDR_ES:
7df20ca4 827 process->execution_stack =
828 g_array_set_size(process->execution_stack,
829 process->execution_stack->len + 1);
830 es = &g_array_index(process->execution_stack, LttvExecutionState,
831 process->execution_stack->len-1);
ce05e187 832 process->state = es;
7df20ca4 833
834 fread(&es->t, sizeof(es->t), 1, fp);
835 es->t = g_quark_from_string(
836 (gchar*)g_ptr_array_index(quarktable, es->t));
837 fread(&es->n, sizeof(es->n), 1, fp);
838 es->n = g_quark_from_string(
839 (gchar*)g_ptr_array_index(quarktable, es->n));
840 fread(&es->s, sizeof(es->s), 1, fp);
841 es->s = g_quark_from_string(
842 (gchar*)g_ptr_array_index(quarktable, es->s));
843 fread(&es->entry, sizeof(es->entry), 1, fp);
844 fread(&es->change, sizeof(es->change), 1, fp);
845 fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
6d0cdf22 846 break;
847 case HDR_USER_STACK:
7df20ca4 848 process->user_stack = g_array_set_size(process->user_stack,
849 process->user_stack->len + 1);
850 address = &g_array_index(process->user_stack, guint64,
851 process->user_stack->len-1);
852 fread(address, sizeof(address), 1, fp);
853 process->current_function = *address;
6d0cdf22 854 break;
855 case HDR_USERTRACE:
7df20ca4 856 fread(&tmpq, sizeof(tmpq), 1, fp);
857 fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
6d0cdf22 858 break;
859 default:
860 ungetc(hdr, fp);
861 goto end_loop;
862 };
863 } while(1);
864end_loop:
d41c66bf 865 return;
6d0cdf22 866}
867
868
869/* Called because a HDR_PROCESS_STATE was found */
870/* Append a saved state to the trace states */
7df20ca4 871void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
6d0cdf22 872{
873 guint i, nb_tracefile, nb_block, offset;
874 guint64 tsc;
d41c66bf 875 LttvTracefileState *tfcs;
6d0cdf22 876
877 LttEventPosition *ep;
878
879 guint nb_cpus;
880
881 int hdr;
882
883 LttTime t;
884
885 LttvAttribute *saved_states_tree, *saved_state_tree;
886
887 LttvAttributeValue value;
ce05e187 888 GTree *pqueue = self->parent.ts_context->pqueue;
6d0cdf22 889 ep = ltt_event_position_new();
890
891 restore_init_state(self);
892
893 fread(&t, sizeof(t), 1, fp);
894
895 do {
896 if(feof(fp) || ferror(fp)) goto end_loop;
897 hdr = fgetc(fp);
7df20ca4 898 if(hdr == EOF) goto end_loop;
6d0cdf22 899
900 switch(hdr) {
901 case HDR_PROCESS:
902 /* Call read_process_state_raw */
7df20ca4 903 read_process_state_raw(self, fp, quarktable);
6d0cdf22 904 break;
905 case HDR_TRACEFILE:
906 case HDR_TRACESET:
907 case HDR_TRACE:
908 case HDR_QUARKS:
909 case HDR_QUARK:
910 case HDR_ES:
911 case HDR_USER_STACK:
912 case HDR_USERTRACE:
913 case HDR_PROCESS_STATE:
914 case HDR_CPU:
7df20ca4 915 ungetc(hdr, fp);
916 goto end_loop;
6d0cdf22 917 break;
918 default:
919 g_error("Error while parsing saved state file : unknown data header %d",
920 hdr);
921 };
922 } while(1);
923end_loop:
924
925 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
926 for(i=0;i<nb_cpus;i++) {
927 int cpu_num;
928 hdr = fgetc(fp);
929 g_assert(hdr == HDR_CPU);
930 fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
931 g_assert(i == cpu_num);
932 fread(&self->running_process[i]->pid,
933 sizeof(self->running_process[i]->pid), 1, fp);
934 }
935
936 nb_tracefile = self->parent.tracefiles->len;
937
938 for(i = 0 ; i < nb_tracefile ; i++) {
939 tfcs =
940 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
941 LttvTracefileContext*, i));
942 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
943 // tfcs->parent.timestamp.tv_sec,
944 // tfcs->parent.timestamp.tv_nsec);
ce05e187 945 g_tree_remove(pqueue, &tfcs->parent);
6d0cdf22 946 hdr = fgetc(fp);
947 g_assert(hdr == HDR_TRACEFILE);
948 fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
949 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
950 * position following : end of trace */
d41c66bf 951 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
6d0cdf22 952 fread(&nb_block, sizeof(nb_block), 1, fp);
953 fread(&offset, sizeof(offset), 1, fp);
954 fread(&tsc, sizeof(tsc), 1, fp);
7df20ca4 955 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
d41c66bf 956 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
957 g_assert(ret == 0);
ce05e187 958 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
6d0cdf22 959 }
960 }
961 g_free(ep);
962
d41c66bf 963 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
6d0cdf22 964 LTTV_STATE_SAVED_STATES);
965 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
966 value = lttv_attribute_add(saved_states_tree,
967 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
968 *(value.v_gobject) = (GObject *)saved_state_tree;
969 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
970 *(value.v_time) = t;
d41c66bf 971 lttv_state_save(self, saved_state_tree);
6d0cdf22 972 g_debug("Saving state at time %lu.%lu", t.tv_sec,
d41c66bf 973 t.tv_nsec);
6d0cdf22 974
975 *(self->max_time_state_recomputed_in_seek) = t;
ce05e187 976
6d0cdf22 977}
978
979/* Called when a HDR_TRACE is found */
7df20ca4 980void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
981 GPtrArray *quarktable)
6d0cdf22 982{
983 int hdr;
984
985 do {
986 if(feof(fp) || ferror(fp)) goto end_loop;
987 hdr = fgetc(fp);
7df20ca4 988 if(hdr == EOF) goto end_loop;
6d0cdf22 989
990 switch(hdr) {
991 case HDR_PROCESS_STATE:
992 /* Call read_process_state_raw */
7df20ca4 993 lttv_state_read_raw(tcs, fp, quarktable);
6d0cdf22 994 break;
995 case HDR_TRACEFILE:
996 case HDR_TRACESET:
997 case HDR_TRACE:
998 case HDR_QUARKS:
999 case HDR_QUARK:
1000 case HDR_ES:
1001 case HDR_USER_STACK:
1002 case HDR_USERTRACE:
1003 case HDR_PROCESS:
1004 case HDR_CPU:
1005 g_error("Error while parsing saved state file :"
1006 " unexpected data header %d",
1007 hdr);
1008 break;
1009 default:
1010 g_error("Error while parsing saved state file : unknown data header %d",
1011 hdr);
1012 };
1013 } while(1);
1014end_loop:
6d0cdf22 1015 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
ce05e187 1016 restore_init_state(tcs);
1017 lttv_process_trace_seek_time(tcs, ltt_time_zero);
1018 return;
6d0cdf22 1019}
1020
1021
1022
dbb7bb09 1023/* Copy each process from an existing hash table to a new one */
1024
308711e5 1025static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
ffd54a90 1026{
308711e5 1027 LttvProcessState *process, *new_process;
ffd54a90 1028
308711e5 1029 GHashTable *new_processes = (GHashTable *)user_data;
ffd54a90 1030
308711e5 1031 guint i;
1032
1033 process = (LttvProcessState *)value;
1034 new_process = g_new(LttvProcessState, 1);
1035 *new_process = *process;
e8f2280c 1036 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1037 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
e05fc742 1038 new_process->execution_stack =
1039 g_array_set_size(new_process->execution_stack,
1040 process->execution_stack->len);
308711e5 1041 for(i = 0 ; i < process->execution_stack->len; i++) {
1042 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1043 g_array_index(process->execution_stack, LttvExecutionState, i);
1044 }
1045 new_process->state = &g_array_index(new_process->execution_stack,
1046 LttvExecutionState, new_process->execution_stack->len - 1);
302efbad 1047 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1048 sizeof(guint64), 0);
1049 new_process->user_stack =
1050 g_array_set_size(new_process->user_stack,
1051 process->user_stack->len);
1052 for(i = 0 ; i < process->user_stack->len; i++) {
1053 g_array_index(new_process->user_stack, guint64, i) =
1054 g_array_index(process->user_stack, guint64, i);
1055 }
052a984f 1056 new_process->current_function = process->current_function;
2a2fa4f0 1057 g_hash_table_insert(new_processes, new_process, new_process);
ffd54a90 1058}
1059
1060
308711e5 1061static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
ffd54a90 1062{
2a2fa4f0 1063 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
ffd54a90 1064
308711e5 1065 g_hash_table_foreach(processes, copy_process_state, new_processes);
1066 return new_processes;
dc877563 1067}
1068
1069
308711e5 1070/* The saved state for each trace contains a member "processes", which
1071 stores a copy of the process table, and a member "tracefiles" with
1072 one entry per tracefile. Each tracefile has a "process" member pointing
1073 to the current process and a "position" member storing the tracefile
1074 position (needed to seek to the current "next" event. */
1075
1076static void state_save(LttvTraceState *self, LttvAttribute *container)
dc877563 1077{
348c6ba8 1078 guint i, nb_tracefile, nb_cpus;
dc877563 1079
308711e5 1080 LttvTracefileState *tfcs;
1081
1082 LttvAttribute *tracefiles_tree, *tracefile_tree;
348c6ba8 1083
1084 guint *running_process;
308711e5 1085
1086 LttvAttributeType type;
1087
1088 LttvAttributeValue value;
1089
1090 LttvAttributeName name;
1091
1092 LttEventPosition *ep;
1093
1094 tracefiles_tree = lttv_attribute_find_subdir(container,
1095 LTTV_STATE_TRACEFILES);
1096
1097 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1098 LTTV_POINTER);
1099 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1100
348c6ba8 1101 /* Add the currently running processes array */
1102 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1103 running_process = g_new(guint, nb_cpus);
1104 for(i=0;i<nb_cpus;i++) {
1105 running_process[i] = self->running_process[i]->pid;
1106 }
1107 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1108 LTTV_POINTER);
1109 *(value.v_pointer) = running_process;
728d0c3e 1110
1111 g_info("State save");
348c6ba8 1112
eed2ef37 1113 nb_tracefile = self->parent.tracefiles->len;
308711e5 1114
1115 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1116 tfcs =
cb03932a 1117 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1118 LttvTracefileContext*, i));
308711e5 1119 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1120 value = lttv_attribute_add(tracefiles_tree, i,
1121 LTTV_GOBJECT);
1122 *(value.v_gobject) = (GObject *)tracefile_tree;
348c6ba8 1123#if 0
308711e5 1124 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1125 LTTV_UINT);
1126 *(value.v_uint) = tfcs->process->pid;
348c6ba8 1127#endif //0
308711e5 1128 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1129 LTTV_POINTER);
3054461a 1130 /* Only save the position if the tfs has not infinite time. */
1131 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1132 // && current_tfcs != tfcs) {
1133 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1986f254 1134 *(value.v_pointer) = NULL;
1135 } else {
1136 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
a5dcde2f 1137 ep = ltt_event_position_new();
eed2ef37 1138 ltt_event_position(e, ep);
308711e5 1139 *(value.v_pointer) = ep;
08b1c66e 1140
eed2ef37 1141 guint nb_block, offset;
1142 guint64 tsc;
08b1c66e 1143 LttTracefile *tf;
eed2ef37 1144 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
728d0c3e 1145 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
eed2ef37 1146 tsc,
08b1c66e 1147 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
308711e5 1148 }
dc877563 1149 }
dc877563 1150}
1151
1152
308711e5 1153static void state_restore(LttvTraceState *self, LttvAttribute *container)
dc877563 1154{
348c6ba8 1155 guint i, nb_tracefile, pid, nb_cpus;
dc877563 1156
308711e5 1157 LttvTracefileState *tfcs;
dc877563 1158
308711e5 1159 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 1160
348c6ba8 1161 guint *running_process;
1162
308711e5 1163 LttvAttributeType type;
dc877563 1164
308711e5 1165 LttvAttributeValue value;
dc877563 1166
308711e5 1167 LttvAttributeName name;
dc877563 1168
80e0221b 1169 gboolean is_named;
c0cb4d12 1170
308711e5 1171 LttEventPosition *ep;
dc877563 1172
27304273 1173 LttvTracesetContext *tsc = self->parent.ts_context;
1174
308711e5 1175 tracefiles_tree = lttv_attribute_find_subdir(container,
1176 LTTV_STATE_TRACEFILES);
dc877563 1177
308711e5 1178 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1179 &value);
1180 g_assert(type == LTTV_POINTER);
1181 lttv_state_free_process_table(self->processes);
1182 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1183
348c6ba8 1184 /* Add the currently running processes array */
1185 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1186 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1187 &value);
1188 g_assert(type == LTTV_POINTER);
1189 running_process = *(value.v_pointer);
1190 for(i=0;i<nb_cpus;i++) {
1191 pid = running_process[i];
1192 self->running_process[i] = lttv_state_find_process(self, i, pid);
1193 g_assert(self->running_process[i] != NULL);
1194 }
1195
1196
eed2ef37 1197 nb_tracefile = self->parent.tracefiles->len;
308711e5 1198
d448fce2 1199 //g_tree_destroy(tsc->pqueue);
1200 //tsc->pqueue = g_tree_new(compare_tracefile);
e7f5e89d 1201
308711e5 1202 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1203 tfcs =
cb03932a 1204 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1205 LttvTracefileContext*, i));
c0cb4d12 1206 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
308711e5 1207 g_assert(type == LTTV_GOBJECT);
1208 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
348c6ba8 1209#if 0
308711e5 1210 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1211 &value);
1212 g_assert(type == LTTV_UINT);
2a2fa4f0 1213 pid = *(value.v_uint);
1214 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
348c6ba8 1215#endif //0
308711e5 1216 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1217 &value);
1218 g_assert(type == LTTV_POINTER);
e7f5e89d 1219 //g_assert(*(value.v_pointer) != NULL);
eed2ef37 1220 ep = *(value.v_pointer);
1221 g_assert(tfcs->parent.t_context != NULL);
27304273 1222
27304273 1223 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
d448fce2 1224 g_tree_remove(tsc->pqueue, tfc);
27304273 1225
1986f254 1226 if(ep != NULL) {
1227 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
1228 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
e7f5e89d 1229 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1986f254 1230 g_tree_insert(tsc->pqueue, tfc, tfc);
728d0c3e 1231 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1986f254 1232 } else {
1233 tfc->timestamp = ltt_time_infinite;
1234 }
dc877563 1235 }
dc877563 1236}
1237
1238
308711e5 1239static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 1240{
348c6ba8 1241 guint i, nb_tracefile, nb_cpus;
dc877563 1242
308711e5 1243 LttvTracefileState *tfcs;
dc877563 1244
308711e5 1245 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 1246
348c6ba8 1247 guint *running_process;
1248
308711e5 1249 LttvAttributeType type;
dc877563 1250
308711e5 1251 LttvAttributeValue value;
dc877563 1252
308711e5 1253 LttvAttributeName name;
dc877563 1254
80e0221b 1255 gboolean is_named;
c0cb4d12 1256
308711e5 1257 LttEventPosition *ep;
dc877563 1258
308711e5 1259 tracefiles_tree = lttv_attribute_find_subdir(container,
1260 LTTV_STATE_TRACEFILES);
c47a6dc6 1261 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 1262 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 1263
308711e5 1264 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1265 &value);
1266 g_assert(type == LTTV_POINTER);
1267 lttv_state_free_process_table(*(value.v_pointer));
1268 *(value.v_pointer) = NULL;
1269 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1270
348c6ba8 1271 /* Free running processes array */
1272 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
728d0c3e 1273 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
348c6ba8 1274 &value);
1275 g_assert(type == LTTV_POINTER);
1276 running_process = *(value.v_pointer);
1277 g_free(running_process);
1278
eed2ef37 1279 nb_tracefile = self->parent.tracefiles->len;
308711e5 1280
1281 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1282 tfcs =
cb03932a 1283 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1284 LttvTracefileContext*, i));
c0cb4d12 1285 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
308711e5 1286 g_assert(type == LTTV_GOBJECT);
1287 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1288
1289 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1290 &value);
1291 g_assert(type == LTTV_POINTER);
1292 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 1293 }
c47a6dc6 1294 g_object_unref(G_OBJECT(tracefiles_tree));
dc877563 1295}
1296
1297
f95bc830 1298static void free_saved_state(LttvTraceState *self)
1299{
1300 guint i, nb;
1301
1302 LttvAttributeType type;
1303
1304 LttvAttributeValue value;
1305
1306 LttvAttributeName name;
1307
80e0221b 1308 gboolean is_named;
c0cb4d12 1309
f95bc830 1310 LttvAttribute *saved_states;
1311
1312 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1313 LTTV_STATE_SAVED_STATES);
1314
1315 nb = lttv_attribute_get_number(saved_states);
1316 for(i = 0 ; i < nb ; i++) {
c0cb4d12 1317 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
f95bc830 1318 g_assert(type == LTTV_GOBJECT);
1319 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1320 }
1321
1322 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
f95bc830 1323}
1324
1325
1326static void
1327create_max_time(LttvTraceState *tcs)
1328{
1329 LttvAttributeValue v;
1330
1331 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1332 LTTV_POINTER, &v);
1333 g_assert(*(v.v_pointer) == NULL);
1334 *(v.v_pointer) = g_new(LttTime,1);
348c6ba8 1335 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
f95bc830 1336}
1337
1338
1339static void
1340get_max_time(LttvTraceState *tcs)
1341{
1342 LttvAttributeValue v;
1343
1344 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1345 LTTV_POINTER, &v);
1346 g_assert(*(v.v_pointer) != NULL);
1347 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1348}
1349
1350
1351static void
1352free_max_time(LttvTraceState *tcs)
1353{
1354 LttvAttributeValue v;
1355
1356 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1357 LTTV_POINTER, &v);
1358 g_free(*(v.v_pointer));
1359 *(v.v_pointer) = NULL;
1360}
1361
1362
1363typedef struct _LttvNameTables {
eed2ef37 1364 // FIXME GQuark *eventtype_names;
f95bc830 1365 GQuark *syscall_names;
5e96e7e3 1366 guint nb_syscalls;
f95bc830 1367 GQuark *trap_names;
5e96e7e3 1368 guint nb_traps;
f95bc830 1369 GQuark *irq_names;
6214c229 1370 guint nb_irqs;
faf074a3 1371 GQuark *soft_irq_names;
6214c229 1372 guint nb_softirqs;
f95bc830 1373} LttvNameTables;
1374
1375
b445142a 1376static void
f95bc830 1377create_name_tables(LttvTraceState *tcs)
b445142a 1378{
1379 int i, nb;
dc877563 1380
eed2ef37 1381 GQuark f_name, e_name;
1382
021eeb41 1383 LttvTraceHook h;
dc877563 1384
eed2ef37 1385 LttvTraceHookByFacility *thf;
b445142a 1386
1387 LttEventType *et;
1388
1389 LttType *t;
1390
1391 GString *fe_name = g_string_new("");
1392
f95bc830 1393 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1394
1395 LttvAttributeValue v;
1396
1397 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1398 LTTV_POINTER, &v);
1399 g_assert(*(v.v_pointer) == NULL);
1400 *(v.v_pointer) = name_tables;
eed2ef37 1401#if 0 // Use iteration over the facilities_by_name and then list all event
1402 // types of each facility
b445142a 1403 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 1404 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 1405 for(i = 0 ; i < nb ; i++) {
1406 et = ltt_trace_eventtype_get(tcs->parent.t, i);
1407 e_name = ltt_eventtype_name(et);
1408 f_name = ltt_facility_name(ltt_eventtype_facility(et));
1409 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 1410 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 1411 }
eed2ef37 1412#endif //0
285468d4 1413 if(!lttv_trace_find_hook(tcs->parent.t,
f5d7967f 1414 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 1415 LTT_FIELD_SYSCALL_ID, 0, 0,
285468d4 1416 NULL, NULL, &h)) {
80e0221b 1417
1418 thf = lttv_trace_hook_get_first(&h);
1419
1420 t = ltt_field_type(thf->f1);
1421 nb = ltt_type_element_number(t);
1422
1423 lttv_trace_hook_destroy(&h);
1424
1425 name_tables->syscall_names = g_new(GQuark, nb);
1426 name_tables->nb_syscalls = nb;
1427
1428 for(i = 0 ; i < nb ; i++) {
1429 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
da5d36a5 1430 if(!name_tables->syscall_names[i]) {
1431 GString *string = g_string_new("");
1432 g_string_printf(string, "syscall %u", i);
1433 name_tables->syscall_names[i] = g_quark_from_string(string->str);
1434 g_string_free(string, TRUE);
1435 }
80e0221b 1436 }
1437
1438 //name_tables->syscall_names = g_new(GQuark, 256);
1439 //for(i = 0 ; i < 256 ; i++) {
1440 // g_string_printf(fe_name, "syscall %d", i);
1441 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1442 //}
1443 } else {
1444 name_tables->syscall_names = NULL;
1445 name_tables->nb_syscalls = 0;
1446 }
285468d4 1447
86c32a8f 1448 if(!lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL_ARCH,
eed2ef37 1449 LTT_EVENT_TRAP_ENTRY,
1450 LTT_FIELD_TRAP_ID, 0, 0,
285468d4 1451 NULL, NULL, &h)) {
eed2ef37 1452
80e0221b 1453 thf = lttv_trace_hook_get_first(&h);
1454
1455 t = ltt_field_type(thf->f1);
1456 //nb = ltt_type_element_number(t);
1457
1458 lttv_trace_hook_destroy(&h);
1459
1460 /*
1461 name_tables->trap_names = g_new(GQuark, nb);
1462 for(i = 0 ; i < nb ; i++) {
1463 name_tables->trap_names[i] = g_quark_from_string(
1464 ltt_enum_string_get(t, i));
1465 }
1466 */
1467 name_tables->nb_traps = 256;
1468 name_tables->trap_names = g_new(GQuark, 256);
1469 for(i = 0 ; i < 256 ; i++) {
1470 g_string_printf(fe_name, "trap %d", i);
1471 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1472 }
1473 } else {
1474 name_tables->trap_names = NULL;
1475 name_tables->nb_traps = 0;
1476 }
b445142a 1477
285468d4 1478 if(!lttv_trace_find_hook(tcs->parent.t,
eed2ef37 1479 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1480 LTT_FIELD_IRQ_ID, 0, 0,
285468d4 1481 NULL, NULL, &h)) {
80e0221b 1482
1483 thf = lttv_trace_hook_get_first(&h);
1484
1485 t = ltt_field_type(thf->f1);
1486 //nb = ltt_type_element_number(t);
1487
1488 lttv_trace_hook_destroy(&h);
1489
1490 /*
1491 name_tables->irq_names = g_new(GQuark, nb);
1492 for(i = 0 ; i < nb ; i++) {
1493 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1494 }
1495 */
1496
6214c229 1497 name_tables->nb_irqs = 256;
80e0221b 1498 name_tables->irq_names = g_new(GQuark, 256);
1499 for(i = 0 ; i < 256 ; i++) {
1500 g_string_printf(fe_name, "irq %d", i);
1501 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1502 }
1503 } else {
6214c229 1504 name_tables->nb_irqs = 0;
80e0221b 1505 name_tables->irq_names = NULL;
1506 }
faf074a3 1507 /*
1508 name_tables->soft_irq_names = g_new(GQuark, nb);
1509 for(i = 0 ; i < nb ; i++) {
1510 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1511 }
1512 */
1513
6214c229 1514 name_tables->nb_softirqs = 256;
faf074a3 1515 name_tables->soft_irq_names = g_new(GQuark, 256);
1516 for(i = 0 ; i < 256 ; i++) {
1517 g_string_printf(fe_name, "softirq %d", i);
1518 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1519 }
1520
1521
b445142a 1522 g_string_free(fe_name, TRUE);
1523}
1524
1525
f95bc830 1526static void
1527get_name_tables(LttvTraceState *tcs)
1528{
1529 LttvNameTables *name_tables;
1530
1531 LttvAttributeValue v;
1532
1533 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1534 LTTV_POINTER, &v);
1535 g_assert(*(v.v_pointer) != NULL);
1536 name_tables = (LttvNameTables *)*(v.v_pointer);
eed2ef37 1537 //tcs->eventtype_names = name_tables->eventtype_names;
f95bc830 1538 tcs->syscall_names = name_tables->syscall_names;
7cd289b0 1539 tcs->nb_syscalls = name_tables->nb_syscalls;
f95bc830 1540 tcs->trap_names = name_tables->trap_names;
5e96e7e3 1541 tcs->nb_traps = name_tables->nb_traps;
f95bc830 1542 tcs->irq_names = name_tables->irq_names;
faf074a3 1543 tcs->soft_irq_names = name_tables->soft_irq_names;
6214c229 1544 tcs->nb_irqs = name_tables->nb_irqs;
1545 tcs->nb_softirqs = name_tables->nb_softirqs;
f95bc830 1546}
1547
1548
b445142a 1549static void
1550free_name_tables(LttvTraceState *tcs)
1551{
f95bc830 1552 LttvNameTables *name_tables;
1553
1554 LttvAttributeValue v;
1555
1556 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1557 LTTV_POINTER, &v);
1558 name_tables = (LttvNameTables *)*(v.v_pointer);
1559 *(v.v_pointer) = NULL;
1560
eed2ef37 1561 // g_free(name_tables->eventtype_names);
285468d4 1562 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1563 if(name_tables->trap_names) g_free(name_tables->trap_names);
1564 if(name_tables->irq_names) g_free(name_tables->irq_names);
1565 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1566 if(name_tables) g_free(name_tables);
b445142a 1567}
dc877563 1568
15b3d537 1569#ifdef HASH_TABLE_DEBUG
1570
1571static void test_process(gpointer key, gpointer value, gpointer user_data)
1572{
1573 LttvProcessState *process = (LttvProcessState *)value;
1574
1575 /* Test for process corruption */
1576 guint stack_len = process->execution_stack->len;
1577}
1578
1579static void hash_table_check(GHashTable *table)
1580{
1581 g_hash_table_foreach(table, test_process, NULL);
1582}
1583
1584
1585#endif
1586
1587
b445142a 1588static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 1589 guint state_id)
dc877563 1590{
b445142a 1591 LttvExecutionState *es;
348c6ba8 1592
348c6ba8 1593 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
ae3d0f50 1594 guint cpu = tfs->cpu;
15b3d537 1595
1596#ifdef HASH_TABLE_DEBUG
1597 hash_table_check(ts->processes);
1598#endif
348c6ba8 1599 LttvProcessState *process = ts->running_process[cpu];
dc877563 1600
b445142a 1601 guint depth = process->execution_stack->len;
dc877563 1602
e05fc742 1603 process->execution_stack =
1604 g_array_set_size(process->execution_stack, depth + 1);
1605 /* Keep in sync */
1606 process->state =
1607 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1608
b445142a 1609 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1610 es->t = t;
1611 es->n = state_id;
1612 es->entry = es->change = tfs->parent.timestamp;
80e0221b 1613 es->cum_cpu_time = ltt_time_zero;
b445142a 1614 es->s = process->state->s;
1615 process->state = es;
dc877563 1616}
1617
b49e54b4 1618/* pop state
1619 * return 1 when empty, else 0 */
1620int lttv_state_pop_state_cleanup(LttvProcessState *process,
80e0221b 1621 LttvTracefileState *tfs)
b49e54b4 1622{
80e0221b 1623 guint cpu = tfs->cpu;
b49e54b4 1624 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1625
1626 guint depth = process->execution_stack->len;
1627
1628 if(depth == 1){
1629 return 1;
1630 }
1631
1632 process->execution_stack =
1633 g_array_set_size(process->execution_stack, depth - 1);
1634 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1635 depth - 2);
1636 process->state->change = tfs->parent.timestamp;
80e0221b 1637
1638 return 0;
b49e54b4 1639}
dc877563 1640
b445142a 1641static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 1642{
ae3d0f50 1643 guint cpu = tfs->cpu;
348c6ba8 1644 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1645 LttvProcessState *process = ts->running_process[cpu];
dc877563 1646
f95bc830 1647 guint depth = process->execution_stack->len;
dc877563 1648
3d27549e 1649 if(process->state->t != t){
00e74b69 1650 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 1651 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 1652 g_info("process state has %s when pop_int is %s\n",
80e0221b 1653 g_quark_to_string(process->state->t),
1654 g_quark_to_string(t));
7b5f6cf1 1655 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 1656 process->pid,
1657 process->ppid,
1658 g_quark_to_string(process->name),
1659 g_quark_to_string(process->brand),
1660 g_quark_to_string(process->state->s));
3d27549e 1661 return;
1662 }
b445142a 1663
f95bc830 1664 if(depth == 1){
00e74b69 1665 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 1666 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1667 return;
1668 }
1669
e05fc742 1670 process->execution_stack =
1671 g_array_set_size(process->execution_stack, depth - 1);
b445142a 1672 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 1673 depth - 2);
b445142a 1674 process->state->change = tfs->parent.timestamp;
dc877563 1675}
1676
6806b3c6 1677struct search_result {
80e0221b 1678 const LttTime *time; /* Requested time */
1679 LttTime *best; /* Best result */
6806b3c6 1680};
1681
1682static gint search_usertrace(gconstpointer a, gconstpointer b)
1683{
80e0221b 1684 const LttTime *elem_time = (const LttTime*)a;
1685 /* Explicit non const cast */
1686 struct search_result *res = (struct search_result *)b;
1687
1688 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1689 /* The usertrace was created before the schedchange */
1690 /* Get larger keys */
1691 return 1;
1692 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1693 /* The usertrace was created after the schedchange time */
1694 /* Get smaller keys */
1695 if(res->best) {
1696 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1697 res->best = elem_time;
1698 }
1699 } else {
1700 res->best = elem_time;
1701 }
1702 return -1;
1703 }
1704 return 0;
6806b3c6 1705}
1706
1707static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
80e0221b 1708 guint pid, const LttTime *timestamp)
1709{
1710 LttvTracefileState *tfs = NULL;
1711 struct search_result res;
1712 /* Find the usertrace associated with a pid and time interval.
1713 * Search in the usertraces by PID (within a hash) and then, for each
1714 * corresponding element of the array, find the first one with creation
1715 * timestamp the lowest, but higher or equal to "timestamp". */
1716 res.time = timestamp;
1717 res.best = NULL;
1718 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1719 if(usertrace_tree) {
1720 g_tree_search(usertrace_tree, search_usertrace, &res);
1721 if(res.best)
1722 tfs = g_tree_lookup(usertrace_tree, res.best);
1723 }
6806b3c6 1724
80e0221b 1725 return tfs;
6806b3c6 1726}
1727
dc877563 1728
2a2fa4f0 1729LttvProcessState *
348c6ba8 1730lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
fcc08e1e 1731 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
dc877563 1732{
1733 LttvProcessState *process = g_new(LttvProcessState, 1);
1734
b445142a 1735 LttvExecutionState *es;
dc877563 1736
348c6ba8 1737 LttvTraceContext *tc = (LttvTraceContext*)tcs;
ba576a78 1738
b445142a 1739 char buffer[128];
ffd54a90 1740
dc877563 1741 process->pid = pid;
fcc08e1e 1742 process->tgid = tgid;
348c6ba8 1743 process->cpu = cpu;
b3fd4c02 1744 process->name = name;
7b5f6cf1 1745 process->brand = LTTV_STATE_UNBRANDED;
348c6ba8 1746 //process->last_cpu = tfs->cpu_name;
1747 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
80e0221b 1748 process->type = LTTV_STATE_USER_THREAD;
1749 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1750 process->current_function = 0; //function 0x0 by default.
7bfd7820 1751
cb03932a 1752 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 1753 g_hash_table_insert(tcs->processes, process, process);
b445142a 1754
1755 if(parent) {
1756 process->ppid = parent->pid;
348c6ba8 1757 process->creation_time = *timestamp;
b445142a 1758 }
2a2fa4f0 1759
1760 /* No parent. This process exists but we are missing all information about
1761 its creation. The birth time is set to zero but we remember the time of
1762 insertion */
1763
b445142a 1764 else {
1765 process->ppid = 0;
2a2fa4f0 1766 process->creation_time = ltt_time_zero;
b445142a 1767 }
1768
348c6ba8 1769 process->insertion_time = *timestamp;
b445142a 1770 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
80e0221b 1771 process->creation_time.tv_nsec);
b445142a 1772 process->pid_time = g_quark_from_string(buffer);
348c6ba8 1773 process->cpu = cpu;
1774 //process->last_cpu = tfs->cpu_name;
1775 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 1776 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1777 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
c607371b 1778 process->execution_stack = g_array_set_size(process->execution_stack, 2);
b445142a 1779 es = process->state = &g_array_index(process->execution_stack,
1780 LttvExecutionState, 0);
1781 es->t = LTTV_STATE_USER_MODE;
1782 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 1783 es->entry = *timestamp;
1784 //g_assert(timestamp->tv_sec != 0);
1785 es->change = *timestamp;
80e0221b 1786 es->cum_cpu_time = ltt_time_zero;
c607371b 1787 es->s = LTTV_STATE_RUN;
1788
1789 es = process->state = &g_array_index(process->execution_stack,
1790 LttvExecutionState, 1);
1791 es->t = LTTV_STATE_SYSCALL;
1792 es->n = LTTV_STATE_SUBMODE_NONE;
1793 es->entry = *timestamp;
1794 //g_assert(timestamp->tv_sec != 0);
1795 es->change = *timestamp;
80e0221b 1796 es->cum_cpu_time = ltt_time_zero;
c3b3b60b 1797 es->s = LTTV_STATE_WAIT_FORK;
80e0221b 1798
1799 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1800 process->user_stack = g_array_sized_new(FALSE, FALSE,
1801 sizeof(guint64), 0);
1802
cbe7c836 1803 return process;
dc877563 1804}
1805
348c6ba8 1806LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 1807 guint pid)
dc877563 1808{
2a2fa4f0 1809 LttvProcessState key;
1810 LttvProcessState *process;
1811
1812 key.pid = pid;
348c6ba8 1813 key.cpu = cpu;
2a2fa4f0 1814 process = g_hash_table_lookup(ts->processes, &key);
dc877563 1815 return process;
1816}
1817
2a2fa4f0 1818LttvProcessState *
348c6ba8 1819lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
d41c66bf 1820 const LttTime *timestamp)
2a2fa4f0 1821{
348c6ba8 1822 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
7bfd7820 1823 LttvExecutionState *es;
348c6ba8 1824
1825 /* Put ltt_time_zero creation time for unexisting processes */
7bfd7820 1826 if(unlikely(process == NULL)) {
80e0221b 1827 process = lttv_state_create_process(ts,
fcc08e1e 1828 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
80e0221b 1829 /* We are not sure is it's a kernel thread or normal thread, put the
1830 * bottom stack state to unknown */
c3b3b60b 1831 process->execution_stack =
1832 g_array_set_size(process->execution_stack, 1);
1833 process->state = es =
1834 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 1835 es->t = LTTV_STATE_MODE_UNKNOWN;
c4a72569 1836 es->s = LTTV_STATE_UNNAMED;
80e0221b 1837 }
2a2fa4f0 1838 return process;
1839}
1840
41c7f803 1841/* FIXME : this function should be called when we receive an event telling that
1842 * release_task has been called in the kernel. In happens generally when
1843 * the parent waits for its child terminaison, but may also happen in special
1844 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1845 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1846 * of a killed thread ground, but isn't the leader.
41c7f803 1847 */
b445142a 1848static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 1849{
ba576a78 1850 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 1851 LttvProcessState key;
ba576a78 1852
2a2fa4f0 1853 key.pid = process->pid;
348c6ba8 1854 key.cpu = process->cpu;
2a2fa4f0 1855 g_hash_table_remove(ts->processes, &key);
b445142a 1856 g_array_free(process->execution_stack, TRUE);
302efbad 1857 g_array_free(process->user_stack, TRUE);
dc877563 1858 g_free(process);
1859}
1860
1861
b445142a 1862static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 1863{
b445142a 1864 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
302efbad 1865 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
dc877563 1866 g_free(value);
1867}
1868
1869
308711e5 1870static void lttv_state_free_process_table(GHashTable *processes)
dc877563 1871{
1872 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 1873 g_hash_table_destroy(processes);
dc877563 1874}
1875
1876
b445142a 1877static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 1878{
ba576a78 1879 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 1880 guint cpu = s->cpu;
1881 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1882 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1883 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1884 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1885 LttField *f = thf->f1;
dc877563 1886
b445142a 1887 LttvExecutionSubmode submode;
1888
80e0221b 1889 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1890 guint syscall = ltt_event_get_unsigned(e, f);
1891
1892 if(syscall < nb_syscalls) {
1893 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1894 syscall];
1895 } else {
1896 /* Fixup an incomplete syscall table */
1897 GString *string = g_string_new("");
7cd289b0 1898 g_string_printf(string, "syscall %u", syscall);
80e0221b 1899 submode = g_quark_from_string(string->str);
1900 g_string_free(string, TRUE);
1901 }
1e304fa1 1902 /* There can be no system call from PID 0 : unknown state */
1903 if(process->pid != 0)
1904 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 1905 return FALSE;
1906}
1907
1908
b445142a 1909static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 1910{
ba576a78 1911 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 1912 guint cpu = s->cpu;
1913 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1914 LttvProcessState *process = ts->running_process[cpu];
dc877563 1915
1e304fa1 1916 /* There can be no system call from PID 0 : unknown state */
1917 if(process->pid != 0)
1918 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 1919 return FALSE;
1920}
1921
1922
b445142a 1923static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 1924{
ba576a78 1925 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1926 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1927 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1928 LttField *f = thf->f1;
dc877563 1929
b445142a 1930 LttvExecutionSubmode submode;
1931
17ddd1f2 1932 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
1933 guint64 trap = ltt_event_get_long_unsigned(e, f);
5e96e7e3 1934
1935 if(trap < nb_traps) {
1936 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
1937 } else {
1938 /* Fixup an incomplete trap table */
1939 GString *string = g_string_new("");
fcc08e1e 1940 g_string_printf(string, "trap %llu", trap);
5e96e7e3 1941 submode = g_quark_from_string(string->str);
1942 g_string_free(string, TRUE);
1943 }
1944
b445142a 1945 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 1946 return FALSE;
1947}
1948
1949
b445142a 1950static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 1951{
ba576a78 1952 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1953
ffd54a90 1954 pop_state(s, LTTV_STATE_TRAP);
dc877563 1955 return FALSE;
1956}
1957
1958
b445142a 1959static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 1960{
ba576a78 1961 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1962 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 1963 guint8 fac_id = ltt_event_facility_id(e);
1964 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 1965 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 1966 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1967 g_assert(thf->f1 != NULL);
1968 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 1969 LttField *f = thf->f1;
dc877563 1970
b445142a 1971 LttvExecutionSubmode submode;
1bb8d3a5 1972 guint64 irq = ltt_event_get_long_unsigned(e, f);
6214c229 1973 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
1974 GString *string;
b445142a 1975
6214c229 1976 if(irq < nb_irqs) {
1977 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
1978 } else {
1979 /* Fixup an incomplete irq table */
1980 GString *string = g_string_new("");
1981 g_string_printf(string, "irq %llu", irq);
1982 submode = g_quark_from_string(string->str);
1983 g_string_free(string, TRUE);
1984 }
b445142a 1985
dc877563 1986 /* Do something with the info about being in user or system mode when int? */
b445142a 1987 push_state(s, LTTV_STATE_IRQ, submode);
598026ba 1988
1989 /* update cpu status */
1990 s->cpu_state->previous_state = s->cpu_state->present_state;
1991 s->cpu_state->present_state = LTTV_CPU_IRQ;
1992
dc877563 1993 return FALSE;
1994}
1995
302efbad 1996static gboolean soft_irq_exit(void *hook_data, void *call_data)
1997{
1998 LttvTracefileState *s = (LttvTracefileState *)call_data;
1999
2000 pop_state(s, LTTV_STATE_SOFT_IRQ);
2001 return FALSE;
2002}
2003
2004
dc877563 2005
b445142a 2006static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 2007{
ba576a78 2008 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 2009
ffd54a90 2010 pop_state(s, LTTV_STATE_IRQ);
598026ba 2011
2012 /* update cpu status */
2013 s->cpu_state->present_state = s->cpu_state->previous_state;
2014
dc877563 2015 return FALSE;
2016}
2017
faf074a3 2018static gboolean soft_irq_entry(void *hook_data, void *call_data)
2019{
2020 LttvTracefileState *s = (LttvTracefileState *)call_data;
2021 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2022 guint8 fac_id = ltt_event_facility_id(e);
2023 guint8 ev_id = ltt_event_eventtype_id(e);
2024 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2025 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2026 g_assert(thf->f1 != NULL);
2027 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2028 LttField *f = thf->f1;
2029
2030 LttvExecutionSubmode submode;
1bb8d3a5 2031 guint64 softirq = ltt_event_get_long_unsigned(e, f);
6214c229 2032 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
2033 GString *string;
faf074a3 2034
6214c229 2035 if(softirq < nb_softirqs) {
2036 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2037 } else {
2038 /* Fixup an incomplete irq table */
2039 GString *string = g_string_new("");
2040 g_string_printf(string, "softirq %llu", softirq);
2041 submode = g_quark_from_string(string->str);
2042 g_string_free(string, TRUE);
2043 }
faf074a3 2044
2045 /* Do something with the info about being in user or system mode when int? */
2046 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2047 return FALSE;
2048}
2049
302efbad 2050static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2051{
2052 guint64 *new_func;
2053
2054 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2055 guint cpu = tfs->cpu;
2056 LttvProcessState *process = ts->running_process[cpu];
faf074a3 2057
302efbad 2058 guint depth = process->user_stack->len;
2059
2060 process->user_stack =
2061 g_array_set_size(process->user_stack, depth + 1);
2062
2063 new_func = &g_array_index(process->user_stack, guint64, depth);
80e0221b 2064 *new_func = funcptr;
9bff13df 2065 process->current_function = funcptr;
302efbad 2066}
2067
2068static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2069{
2070 guint cpu = tfs->cpu;
2071 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2072 LttvProcessState *process = ts->running_process[cpu];
2073
302efbad 2074 if(process->current_function != funcptr){
2075 g_info("Different functions (%lu.%09lu): ignore it\n",
2076 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2077 g_info("process state has %llu when pop_function is %llu\n",
80e0221b 2078 process->current_function, funcptr);
7b5f6cf1 2079 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 2080 process->pid,
2081 process->ppid,
2082 g_quark_to_string(process->name),
2083 g_quark_to_string(process->brand),
2084 g_quark_to_string(process->state->s));
302efbad 2085 return;
2086 }
9bff13df 2087 guint depth = process->user_stack->len;
302efbad 2088
2089 if(depth == 0){
2090 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2091 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2092 return;
2093 }
2094
2095 process->user_stack =
2096 g_array_set_size(process->user_stack, depth - 1);
2097 process->current_function =
80e0221b 2098 g_array_index(process->user_stack, guint64, depth - 2);
302efbad 2099}
2100
2101
2102static gboolean function_entry(void *hook_data, void *call_data)
faf074a3 2103{
2104 LttvTracefileState *s = (LttvTracefileState *)call_data;
302efbad 2105 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2106 guint8 fac_id = ltt_event_facility_id(e);
2107 guint8 ev_id = ltt_event_eventtype_id(e);
2108 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2109 g_assert(thf->f1 != NULL);
2110 LttField *f = thf->f1;
80e0221b 2111 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
faf074a3 2112
302efbad 2113 push_function(s, funcptr);
faf074a3 2114 return FALSE;
2115}
2116
302efbad 2117static gboolean function_exit(void *hook_data, void *call_data)
2118{
2119 LttvTracefileState *s = (LttvTracefileState *)call_data;
2120 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2121 guint8 fac_id = ltt_event_facility_id(e);
2122 guint8 ev_id = ltt_event_eventtype_id(e);
2123 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2124 g_assert(thf->f1 != NULL);
2125 LttField *f = thf->f1;
80e0221b 2126 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
302efbad 2127
2128 LttvExecutionSubmode submode;
2129
2130 pop_function(s, funcptr);
2131 return FALSE;
2132}
dc877563 2133
b445142a 2134static gboolean schedchange(void *hook_data, void *call_data)
dc877563 2135{
ba576a78 2136 LttvTracefileState *s = (LttvTracefileState *)call_data;
ae3d0f50 2137 guint cpu = s->cpu;
348c6ba8 2138 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2139 LttvProcessState *process = ts->running_process[cpu];
48b002b8 2140 LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 2141
eed2ef37 2142 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2143 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 2144 guint pid_in, pid_out;
7092fb86 2145 gint64 state_out;
dc877563 2146
eed2ef37 2147 pid_out = ltt_event_get_unsigned(e, thf->f1);
2148 pid_in = ltt_event_get_unsigned(e, thf->f2);
7092fb86 2149 state_out = ltt_event_get_long_int(e, thf->f3);
348c6ba8 2150
2151 if(likely(process != NULL)) {
b445142a 2152
f95bc830 2153 /* We could not know but it was not the idle process executing.
2154 This should only happen at the beginning, before the first schedule
2155 event, and when the initial information (current process for each CPU)
2156 is missing. It is not obvious how we could, after the fact, compensate
2157 the wrongly attributed statistics. */
2158
240f1fea 2159 //This test only makes sense once the state is known and if there is no
48b002b8 2160 //missing events. We need to silently ignore schedchange coming after a
80e0221b 2161 //process_free, or it causes glitches. (FIXME)
348c6ba8 2162 //if(unlikely(process->pid != pid_out)) {
2163 // g_assert(process->pid == 0);
240f1fea 2164 //}
c4a72569 2165 if(process->pid == 0
2166 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2167 if(pid_out == 0) {
2168 /* Scheduling out of pid 0 at beginning of the trace :
2169 * we know for sure it is in syscall mode at this point. */
2170 g_assert(process->execution_stack->len == 1);
2171 process->state->t = LTTV_STATE_SYSCALL;
2172 process->state->s = LTTV_STATE_WAIT;
2173 process->state->change = s->parent.timestamp;
d3670e3d 2174 process->state->entry = s->parent.timestamp;
c4a72569 2175 }
dbd243b1 2176 } else {
c4a72569 2177 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2178 process->state->s = LTTV_STATE_ZOMBIE;
2179 process->state->change = s->parent.timestamp;
2180 } else {
2181 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2182 else process->state->s = LTTV_STATE_WAIT;
2183 process->state->change = s->parent.timestamp;
2184 }
2185
5fe0b9ca 2186 if(state_out == 32 || state_out == 128)
2187 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
c4a72569 2188 /* see sched.h for states */
791dffa6 2189 }
dc877563 2190 }
348c6ba8 2191 process = ts->running_process[cpu] =
2192 lttv_state_find_process_or_create(
2193 (LttvTraceState*)s->parent.t_context,
2194 cpu, pid_in,
2195 &s->parent.timestamp);
2196 process->state->s = LTTV_STATE_RUN;
2197 process->cpu = cpu;
80e0221b 2198 if(process->usertrace)
2199 process->usertrace->cpu = cpu;
348c6ba8 2200 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2201 process->state->change = s->parent.timestamp;
44ffb95f 2202
2203 /* update cpu status */
2204 if(pid_in == 0)
2205 s->cpu_state->present_state = LTTV_CPU_IDLE;
2206 else
2207 s->cpu_state->present_state = LTTV_CPU_BUSY;
2208
dc877563 2209 return FALSE;
2210}
2211
eed2ef37 2212static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2213{
eed2ef37 2214 LttvTracefileState *s = (LttvTracefileState *)call_data;
2215 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2216 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2217 guint parent_pid;
fcc08e1e 2218 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2219 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
4ad73431 2220 LttvProcessState *zombie_process;
ae3d0f50 2221 guint cpu = s->cpu;
348c6ba8 2222 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2223 LttvProcessState *process = ts->running_process[cpu];
26275aa2 2224 LttvProcessState *child_process;
2cdc690b 2225
eed2ef37 2226 /* Parent PID */
b3fd4c02 2227 parent_pid = ltt_event_get_unsigned(e, thf->f1);
eed2ef37 2228
2cdc690b 2229 /* Child PID */
b3fd4c02 2230 child_pid = ltt_event_get_unsigned(e, thf->f2);
33bdc8dd 2231 s->parent.target_pid = child_pid;
2cdc690b 2232
fcc08e1e 2233 /* Child TGID */
2234 if(thf->f3) child_tgid = ltt_event_get_unsigned(e, thf->f3);
2235 else child_tgid = 0;
2236
15b3d537 2237 /* Mathieu : it seems like the process might have been scheduled in before the
2238 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 2239 * in a SMP case where we don't have enough precision on the clocks.
2240 *
2241 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2242#if 0
348c6ba8 2243 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 2244
1d1df11d 2245 if(unlikely(zombie_process != NULL)) {
4ad73431 2246 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 2247 * has been released. FIXME : should know when release_task happens instead.
4ad73431 2248 */
15b3d537 2249 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2250 guint i;
2251 for(i=0; i< num_cpus; i++) {
5ac05980 2252 g_assert(zombie_process != ts->running_process[i]);
15b3d537 2253 }
2254
4ad73431 2255 exit_process(s, zombie_process);
2256 }
791dffa6 2257#endif //0
348c6ba8 2258 g_assert(process->pid != child_pid);
eed2ef37 2259 // FIXME : Add this test in the "known state" section
348c6ba8 2260 // g_assert(process->pid == parent_pid);
26275aa2 2261 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2262 if(child_process == NULL) {
ab893fb1 2263 child_process = lttv_state_create_process(ts, process, cpu,
fcc08e1e 2264 child_pid, child_tgid,
2265 LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 2266 } else {
2267 /* The process has already been created : due to time imprecision between
791dffa6 2268 * multiple CPUs : it has been scheduled in before creation. Note that we
2269 * shouldn't have this kind of imprecision.
26275aa2 2270 *
2271 * Simply put a correct parent.
2272 */
6806b3c6 2273 g_assert(0); /* This is a problematic case : the process has been created
2274 before the fork event */
26275aa2 2275 child_process->ppid = process->pid;
fcc08e1e 2276 child_process->tgid = child_tgid;
26275aa2 2277 }
0292757b 2278 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2279 child_process->name = process->name;
2280 child_process->brand = process->brand;
4ad73431 2281
dc877563 2282 return FALSE;
2283}
2284
89f8741a 2285/* We stamp a newly created process as kernel_thread.
2286 * The thread should not be running yet. */
7bfd7820 2287static gboolean process_kernel_thread(void *hook_data, void *call_data)
2288{
2289 LttvTracefileState *s = (LttvTracefileState *)call_data;
2290 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2291 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2292 guint pid;
ae3d0f50 2293 guint cpu = s->cpu;
7bfd7820 2294 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2295 LttvProcessState *process;
2296 LttvExecutionState *es;
2297
2298 /* PID */
61c8808e 2299 pid = (guint)ltt_event_get_long_unsigned(e, thf->f1);
33bdc8dd 2300 s->parent.target_pid = pid;
7bfd7820 2301
61c8808e 2302 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2303 &ltt_time_zero);
15f3a340 2304 process->execution_stack =
2305 g_array_set_size(process->execution_stack, 1);
2306 es = process->state =
2307 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2308 es->t = LTTV_STATE_SYSCALL;
2309 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 2310
80e0221b 2311 return FALSE;
7bfd7820 2312}
dc877563 2313
eed2ef37 2314static gboolean process_exit(void *hook_data, void *call_data)
dc877563 2315{
eed2ef37 2316 LttvTracefileState *s = (LttvTracefileState *)call_data;
2317 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2318 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2319 LttField *f;
2320 guint pid;
ae3d0f50 2321 guint cpu = s->cpu;
348c6ba8 2322 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
6f54e0f4 2323 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 2324
2325 pid = ltt_event_get_unsigned(e, thf->f1);
33bdc8dd 2326 s->parent.target_pid = pid;
eed2ef37 2327
2328 // FIXME : Add this test in the "known state" section
348c6ba8 2329 // g_assert(process->pid == pid);
eed2ef37 2330
6f54e0f4 2331 process = lttv_state_find_process(ts, ANY_CPU, pid);
348c6ba8 2332 if(likely(process != NULL)) {
2333 process->state->s = LTTV_STATE_EXIT;
2cdc690b 2334 }
2335 return FALSE;
2cdc690b 2336}
2337
eed2ef37 2338static gboolean process_free(void *hook_data, void *call_data)
2da61677 2339{
eed2ef37 2340 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 2341 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 2342 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2343 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 2344 guint release_pid;
2345 LttvProcessState *process;
2346
2347 /* PID of the process to release */
eed2ef37 2348 release_pid = ltt_event_get_unsigned(e, thf->f1);
33bdc8dd 2349 s->parent.target_pid = release_pid;
15b3d537 2350
2351 g_assert(release_pid != 0);
2da61677 2352
348c6ba8 2353 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 2354
2355 if(likely(process != NULL)) {
2356 /* release_task is happening at kernel level : we can now safely release
2357 * the data structure of the process */
5562ddce 2358 //This test is fun, though, as it may happen that
2359 //at time t : CPU 0 : process_free
2360 //at time t+150ns : CPU 1 : schedule out
2361 //Clearly due to time imprecision, we disable it. (Mathieu)
2362 //If this weird case happen, we have no choice but to put the
2363 //Currently running process on the cpu to 0.
791dffa6 2364 //I re-enable it following time precision fixes. (Mathieu)
2365 //Well, in the case where an process is freed by a process on another CPU
2366 //and still scheduled, it happens that this is the schedchange that will
2367 //drop the last reference count. Do not free it here!
0bd2f89c 2368 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2369 guint i;
2370 for(i=0; i< num_cpus; i++) {
5562ddce 2371 //g_assert(process != ts->running_process[i]);
2372 if(process == ts->running_process[i]) {
791dffa6 2373 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2374 break;
5562ddce 2375 }
0bd2f89c 2376 }
6f54e0f4 2377 if(i == num_cpus) /* process is not scheduled */
2378 exit_process(s, process);
2da61677 2379 }
2380
2381 return FALSE;
2382}
2383
f4b88a7d 2384
2385static gboolean process_exec(void *hook_data, void *call_data)
2386{
2387 LttvTracefileState *s = (LttvTracefileState *)call_data;
2388 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2389 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2390 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
743e50fd 2391 //gchar *name;
ae3d0f50 2392 guint cpu = s->cpu;
f4b88a7d 2393 LttvProcessState *process = ts->running_process[cpu];
2394
f63ebe51 2395#if 0//how to use a sequence that must be transformed in a string
f4b88a7d 2396 /* PID of the process to release */
743e50fd 2397 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
2398 //name = ltt_event_get_string(e, thf->f1);
f2923fb2 2399 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
2400 gchar *name_begin =
2401 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 2402 gchar *null_term_name = g_new(gchar, name_len+1);
2403 memcpy(null_term_name, name_begin, name_len);
2404 null_term_name[name_len] = '\0';
743e50fd 2405 process->name = g_quark_from_string(null_term_name);
f63ebe51 2406#endif //0
2407
7092fb86 2408 process->name = g_quark_from_string(ltt_event_get_string(e, thf->f1));
0292757b 2409 process->brand = LTTV_STATE_UNBRANDED;
f63ebe51 2410 //g_free(null_term_name);
f4b88a7d 2411 return FALSE;
2412}
2413
7b5f6cf1 2414static gboolean thread_brand(void *hook_data, void *call_data)
2415{
2416 LttvTracefileState *s = (LttvTracefileState *)call_data;
2417 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2418 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2419 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2420 gchar *name;
2421 guint cpu = s->cpu;
2422 LttvProcessState *process = ts->running_process[cpu];
2423
2424 name = ltt_event_get_string(e, thf->f1);
2425 process->brand = g_quark_from_string(name);
2426
2427 return FALSE;
2428}
2429
c3b3b60b 2430static void fix_process(gpointer key, gpointer value,
2431 gpointer user_data)
2432{
2433 LttvProcessState *process;
2434 LttvExecutionState *es;
2435 process = (LttvProcessState *)value;
2436 LttvTracefileContext *tfc = (LttvTracefileContext *)user_data;
2437 LttTime *timestamp = (LttTime*)user_data;
2438
c3b3b60b 2439 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2b25224d 2440 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2441 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2442 es->t = LTTV_STATE_SYSCALL;
2b25224d 2443 es->n = LTTV_STATE_SUBMODE_NONE;
2444 es->entry = *timestamp;
2445 es->change = *timestamp;
2446 es->cum_cpu_time = ltt_time_zero;
c4a72569 2447 if(es->s == LTTV_STATE_UNNAMED)
2448 es->s = LTTV_STATE_WAIT;
c3b3b60b 2449 }
2450 } else {
2b25224d 2451 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2452 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
c3b3b60b 2453 es->t = LTTV_STATE_USER_MODE;
2454 es->n = LTTV_STATE_SUBMODE_NONE;
2455 es->entry = *timestamp;
2456 //g_assert(timestamp->tv_sec != 0);
2457 es->change = *timestamp;
2458 es->cum_cpu_time = ltt_time_zero;
c4a72569 2459 if(es->s == LTTV_STATE_UNNAMED)
2460 es->s = LTTV_STATE_RUN;
c3b3b60b 2461
2b25224d 2462 if(process->execution_stack->len == 1) {
89f8741a 2463 /* Still in bottom unknown mode, means never did a system call
2464 * May be either in user mode, syscall mode, running or waiting.*/
2465 /* FIXME : we may be tagging syscall mode when being user mode */
2b25224d 2466 process->execution_stack =
2467 g_array_set_size(process->execution_stack, 2);
2468 es = process->state = &g_array_index(process->execution_stack,
c3b3b60b 2469 LttvExecutionState, 1);
2b25224d 2470 es->t = LTTV_STATE_SYSCALL;
2471 es->n = LTTV_STATE_SUBMODE_NONE;
2472 es->entry = *timestamp;
2473 //g_assert(timestamp->tv_sec != 0);
2474 es->change = *timestamp;
2475 es->cum_cpu_time = ltt_time_zero;
b59b7222 2476 if(es->s == LTTV_STATE_WAIT_FORK)
2477 es->s = LTTV_STATE_WAIT;
2b25224d 2478 }
c3b3b60b 2479 }
2480 }
2481}
2482
2483static gboolean statedump_end(void *hook_data, void *call_data)
2484{
2485 LttvTracefileState *s = (LttvTracefileState *)call_data;
2486 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2487 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2488 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2489 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2490
2491 /* For all processes */
2492 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2493 /* else, if stack[0] is unknown, set to user mode, running */
2494
2495 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
2496}
2497
b3fd4c02 2498static gboolean enum_process_state(void *hook_data, void *call_data)
2499{
2500 LttvTracefileState *s = (LttvTracefileState *)call_data;
2501 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
80e0221b 2502 //It's slow : optimise later by doing this before reading trace.
2503 LttEventType *et = ltt_event_eventtype(e);
2504 //
b3fd4c02 2505 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2506 guint parent_pid;
2507 guint pid;
fcc08e1e 2508 guint tgid;
b3fd4c02 2509 gchar * command;
ae3d0f50 2510 guint cpu = s->cpu;
b3fd4c02 2511 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2512 LttvProcessState *process = ts->running_process[cpu];
2513 LttvProcessState *parent_process;
fcc08e1e 2514 LttField *f4, *f5, *f6, *f7, *f8;
80e0221b 2515 GQuark type, mode, submode, status;
2516 LttvExecutionState *es;
c4a72569 2517 guint i, nb_cpus;
f4b88a7d 2518
b3fd4c02 2519 /* PID */
2520 pid = ltt_event_get_unsigned(e, thf->f1);
e38d9ea0 2521 s->parent.target_pid = pid;
2522
b3fd4c02 2523 /* Parent PID */
2524 parent_pid = ltt_event_get_unsigned(e, thf->f2);
2525
2526 /* Command name */
2527 command = ltt_event_get_string(e, thf->f3);
2528
80e0221b 2529 /* type */
2530 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
2531 type = ltt_enum_string_get(ltt_field_type(f4),
2532 ltt_event_get_unsigned(e, f4));
b3fd4c02 2533
80e0221b 2534 /* mode */
2535 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
2536 mode = ltt_enum_string_get(ltt_field_type(f5),
2537 ltt_event_get_unsigned(e, f5));
b3fd4c02 2538
80e0221b 2539 /* submode */
2540 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
2541 submode = ltt_enum_string_get(ltt_field_type(f6),
2542 ltt_event_get_unsigned(e, f6));
b3fd4c02 2543
80e0221b 2544 /* status */
2545 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
2546 status = ltt_enum_string_get(ltt_field_type(f7),
2547 ltt_event_get_unsigned(e, f7));
e62e7f3a 2548
fcc08e1e 2549 /* TGID */
2550 f8 = ltt_eventtype_field_by_name(et, LTT_FIELD_TGID);
2551 if(f8) tgid = ltt_event_get_unsigned(e, f8);
2552 else tgid = 0;
2553
c4a72569 2554
2555 if(pid == 0) {
2556 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2557 for(i=0; i<nb_cpus; i++) {
2558 process = lttv_state_find_process(ts, i, pid);
2559 g_assert(process != NULL);
2560
2561 process->ppid = parent_pid;
2562 process->tgid = tgid;
2563 process->name = g_quark_from_string(command);
2564 es =
2565 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2566 process->type = LTTV_STATE_KERNEL_THREAD;
c4a72569 2567 }
2568
2569 } else {
2570 /* The process might exist if a process was forked while performing the
2571 * state dump. */
2572 process = lttv_state_find_process(ts, ANY_CPU, pid);
2573 if(process == NULL) {
2574 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2575 process = lttv_state_create_process(ts, parent_process, cpu,
2576 pid, tgid, g_quark_from_string(command),
2577 &s->parent.timestamp);
2578
2579 /* Keep the stack bottom : a running user mode */
2580 /* Disabled because of inconsistencies in the current statedump states. */
2581 if(type == LTTV_STATE_KERNEL_THREAD) {
2582 /* Only keep the bottom
2583 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2584 /* Will cause expected trap when in fact being syscall (even after end of
2585 * statedump event)
2586 * Will cause expected interrupt when being syscall. (only before end of
2587 * statedump event) */
2588 // This will cause a "popping last state on stack, ignoring it."
2589 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2590 es = process->state = &g_array_index(process->execution_stack,
2591 LttvExecutionState, 0);
2592 process->type = LTTV_STATE_KERNEL_THREAD;
2593 es->t = LTTV_STATE_MODE_UNKNOWN;
2594 es->s = LTTV_STATE_UNNAMED;
2595 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2596 #if 0
2597 es->t = LTTV_STATE_SYSCALL;
2598 es->s = status;
2599 es->n = submode;
2600 #endif //0
2601 } else {
2602 /* User space process :
2603 * bottom : user mode
2604 * either currently running or scheduled out.
2605 * can be scheduled out because interrupted in (user mode or in syscall)
2606 * or because of an explicit call to the scheduler in syscall. Note that
2607 * the scheduler call comes after the irq_exit, so never in interrupt
2608 * context. */
2609 // temp workaround : set size to 1 : only have user mode bottom of stack.
2610 // will cause g_info message of expected syscall mode when in fact being
2611 // in user mode. Can also cause expected trap when in fact being user
2612 // mode in the event of a page fault reenabling interrupts in the handler.
2613 // Expected syscall and trap can also happen after the end of statedump
2614 // This will cause a "popping last state on stack, ignoring it."
2615 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2616 es = process->state = &g_array_index(process->execution_stack,
2617 LttvExecutionState, 0);
2618 es->t = LTTV_STATE_MODE_UNKNOWN;
2619 es->s = LTTV_STATE_UNNAMED;
2620 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2621 #if 0
2622 es->t = LTTV_STATE_USER_MODE;
2623 es->s = status;
2624 es->n = submode;
2625 #endif //0
2626 }
2627 #if 0
2628 /* UNKNOWN STATE */
2629 {
2630 es = process->state = &g_array_index(process->execution_stack,
2631 LttvExecutionState, 1);
2632 es->t = LTTV_STATE_MODE_UNKNOWN;
2633 es->s = LTTV_STATE_UNNAMED;
2634 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2635 }
2636 #endif //0
80e0221b 2637 } else {
c4a72569 2638 /* The process has already been created :
2639 * Probably was forked while dumping the process state or
2640 * was simply scheduled in prior to get the state dump event.
2641 */
2642 process->ppid = parent_pid;
2643 process->tgid = tgid;
2644 process->name = g_quark_from_string(command);
2645 process->type = type;
2646 es =
2647 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2648#if 0
c4a72569 2649 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2650 if(type == LTTV_STATE_KERNEL_THREAD)
2651 es->t = LTTV_STATE_SYSCALL;
2652 else
2653 es->t = LTTV_STATE_USER_MODE;
2654 }
cab321cf 2655#endif //0
c4a72569 2656 /* Don't mess around with the stack, it will eventually become
2657 * ok after the end of state dump. */
80e0221b 2658 }
b3fd4c02 2659 }
2660
2661 return FALSE;
2662}
f4b88a7d 2663
58c88a41 2664gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
2665{
2666 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2667
2668 lttv_state_add_event_hooks(tss);
2669
2670 return 0;
2671}
dc877563 2672
308711e5 2673void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 2674{
ba576a78 2675 LttvTraceset *traceset = self->parent.ts;
dc877563 2676
eed2ef37 2677 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 2678
ba576a78 2679 LttvTraceState *ts;
dc877563 2680
ba576a78 2681 LttvTracefileState *tfs;
dc877563 2682
dc877563 2683 GArray *hooks;
2684
eed2ef37 2685 LttvTraceHookByFacility *thf;
2686
2687 LttvTraceHook *hook;
dc877563 2688
2689 LttvAttributeValue val;
2690
9d239bd9 2691 gint ret;
80e0221b 2692 gint hn;
9d239bd9 2693
ba576a78 2694 nb_trace = lttv_traceset_number(traceset);
dc877563 2695 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 2696 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 2697
2698 /* Find the eventtype id for the following events and register the
2699 associated by id hooks. */
2700
c3b3b60b 2701 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
2702 hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
80e0221b 2703 hn = 0;
b445142a 2704
9d239bd9 2705 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 2706 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 2707 LTT_FIELD_SYSCALL_ID, 0, 0,
302efbad 2708 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2709 if(ret) hn--;
cbe7c836 2710
9d239bd9 2711 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 2712 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
eed2ef37 2713 0, 0, 0,
302efbad 2714 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2715 if(ret) hn--;
cbe7c836 2716
9d239bd9 2717 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2718 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
eed2ef37 2719 LTT_FIELD_TRAP_ID, 0, 0,
302efbad 2720 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2721 if(ret) hn--;
cbe7c836 2722
9d239bd9 2723 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2724 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
eed2ef37 2725 0, 0, 0,
302efbad 2726 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2727 if(ret) hn--;
cbe7c836 2728
9d239bd9 2729 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 2730 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
2731 LTT_FIELD_IRQ_ID, 0, 0,
302efbad 2732 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2733 if(ret) hn--;
cbe7c836 2734
9d239bd9 2735 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 2736 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
2737 0, 0, 0,
302efbad 2738 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2739 if(ret) hn--;
cbe7c836 2740
faf074a3 2741 ret = lttv_trace_find_hook(ts->parent.t,
2742 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
2743 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
302efbad 2744 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2745 if(ret) hn--;
faf074a3 2746
2747 ret = lttv_trace_find_hook(ts->parent.t,
2748 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
2749 0, 0, 0,
302efbad 2750 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2751 if(ret) hn--;
faf074a3 2752
9d239bd9 2753 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2754 LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
f63ebe51 2755 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
302efbad 2756 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2757 if(ret) hn--;
cbe7c836 2758
9d239bd9 2759 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2760 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FORK,
f63ebe51 2761 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, LTT_FIELD_CHILD_TGID,
302efbad 2762 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2763 if(ret) hn--;
eed2ef37 2764
7bfd7820 2765 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2766 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_KTHREAD_CREATE,
7bfd7820 2767 LTT_FIELD_PID, 0, 0,
302efbad 2768 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
80e0221b 2769 hn++));
2770 if(ret) hn--;
7bfd7820 2771
9d239bd9 2772 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2773 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
eed2ef37 2774 LTT_FIELD_PID, 0, 0,
302efbad 2775 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2776 if(ret) hn--;
eed2ef37 2777
9d239bd9 2778 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2779 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FREE,
eed2ef37 2780 LTT_FIELD_PID, 0, 0,
302efbad 2781 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2782 if(ret) hn--;
2cdc690b 2783
f4b88a7d 2784 ret = lttv_trace_find_hook(ts->parent.t,
2785 LTT_FACILITY_FS, LTT_EVENT_EXEC,
2786 LTT_FIELD_FILENAME, 0, 0,
302efbad 2787 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2788 if(ret) hn--;
f4b88a7d 2789
7b5f6cf1 2790 ret = lttv_trace_find_hook(ts->parent.t,
2791 LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
2792 LTT_FIELD_NAME, 0, 0,
2793 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2794 if(ret) hn--;
7b5f6cf1 2795
b3fd4c02 2796 /* statedump-related hooks */
2797 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2798 LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
b3fd4c02 2799 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
302efbad 2800 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2801 if(ret) hn--;
f4b88a7d 2802
c3b3b60b 2803 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 2804 LTT_FACILITY_LIST, LTT_EVENT_STATEDUMP_END,
c3b3b60b 2805 0, 0, 0,
2806 statedump_end, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2807 if(ret) hn--;
2808
302efbad 2809 ret = lttv_trace_find_hook(ts->parent.t,
2810 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2811 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2812 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2813 if(ret) hn--;
302efbad 2814
2815 ret = lttv_trace_find_hook(ts->parent.t,
2816 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2817 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2818 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 2819 if(ret) hn--;
302efbad 2820
2821 hooks = g_array_set_size(hooks, hn);
2822
a5ba1787 2823 /* Add these hooks to each event_by_id hooks list */
dc877563 2824
eed2ef37 2825 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 2826
dc877563 2827 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2828 tfs =
9d239bd9 2829 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2830 LttvTracefileContext*, j));
dc877563 2831
2832 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 2833 hook = &g_array_index(hooks, LttvTraceHook, k);
2834 for(l=0;l<hook->fac_list->len;l++) {
2835 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2836 lttv_hooks_add(
2837 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2838 thf->h,
d052ffc3 2839 thf,
eed2ef37 2840 LTTV_PRIO_STATE);
2841 }
ffd54a90 2842 }
dc877563 2843 }
f0b795e0 2844 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 2845 *(val.v_pointer) = hooks;
dc877563 2846 }
2847}
2848
58c88a41 2849gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2850{
2851 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2852
2853 lttv_state_remove_event_hooks(tss);
2854
2855 return 0;
2856}
dc877563 2857
308711e5 2858void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 2859{
ba576a78 2860 LttvTraceset *traceset = self->parent.ts;
dc877563 2861
eed2ef37 2862 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 2863
ba576a78 2864 LttvTraceState *ts;
dc877563 2865
ba576a78 2866 LttvTracefileState *tfs;
dc877563 2867
dc877563 2868 GArray *hooks;
2869
eed2ef37 2870 LttvTraceHook *hook;
2871
2872 LttvTraceHookByFacility *thf;
dc877563 2873
2874 LttvAttributeValue val;
2875
ba576a78 2876 nb_trace = lttv_traceset_number(traceset);
dc877563 2877 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 2878 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
7df20ca4 2879
f0b795e0 2880 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 2881 hooks = *(val.v_pointer);
dc877563 2882
a5ba1787 2883 /* Remove these hooks from each event_by_id hooks list */
dc877563 2884
eed2ef37 2885 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 2886
dc877563 2887 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2888 tfs =
cb03932a 2889 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2890 LttvTracefileContext*, j));
dc877563 2891
2892 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 2893 hook = &g_array_index(hooks, LttvTraceHook, k);
2894 for(l=0;l<hook->fac_list->len;l++) {
2895 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2896
2897 lttv_hooks_remove_data(
2898 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2899 thf->h,
d052ffc3 2900 thf);
eed2ef37 2901 }
ffd54a90 2902 }
dc877563 2903 }
1986f254 2904 for(k = 0 ; k < hooks->len ; k++)
2905 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 2906 g_array_free(hooks, TRUE);
2907 }
2908}
2909
eed2ef37 2910static gboolean state_save_event_hook(void *hook_data, void *call_data)
2911{
2912 guint *event_count = (guint*)hook_data;
2913
2914 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2915 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2916 return FALSE;
2917 else
18c87975 2918 *event_count = 0;
eed2ef37 2919
2920 LttvTracefileState *self = (LttvTracefileState *)call_data;
2921
2922 LttvTracefileState *tfcs;
2923
2924 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2925
2926 LttEventPosition *ep;
2927
2928 guint i;
2929
2930 LttTracefile *tf;
2931
2932 LttvAttribute *saved_states_tree, *saved_state_tree;
2933
2934 LttvAttributeValue value;
2935
2936 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2937 LTTV_STATE_SAVED_STATES);
2938 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2939 value = lttv_attribute_add(saved_states_tree,
2940 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2941 *(value.v_gobject) = (GObject *)saved_state_tree;
2942 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2943 *(value.v_time) = self->parent.timestamp;
2944 lttv_state_save(tcs, saved_state_tree);
2945 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2946 self->parent.timestamp.tv_nsec);
2947
2948 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2949
2950 return FALSE;
2951}
2952
14aecf75 2953static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2954{
2955 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2956
2957 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2958
2959 return FALSE;
2960}
2961
ae3d0f50 2962guint lttv_state_current_cpu(LttvTracefileState *tfs)
2963{
80e0221b 2964 return tfs->cpu;
ae3d0f50 2965}
2966
2967
2968
eed2ef37 2969#if 0
08b1c66e 2970static gboolean block_start(void *hook_data, void *call_data)
308711e5 2971{
dbb7bb09 2972 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 2973
dbb7bb09 2974 LttvTracefileState *tfcs;
308711e5 2975
dbb7bb09 2976 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2977
2978 LttEventPosition *ep;
308711e5 2979
dbb7bb09 2980 guint i, nb_block, nb_event, nb_tracefile;
308711e5 2981
2982 LttTracefile *tf;
2983
2984 LttvAttribute *saved_states_tree, *saved_state_tree;
2985
2986 LttvAttributeValue value;
2987
dbb7bb09 2988 ep = ltt_event_position_new();
eed2ef37 2989
2990 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 2991
2992 /* Count the number of events added since the last block end in any
2993 tracefile. */
2994
2995 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 2996 tfcs =
2997 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2998 LttvTracefileContext, i));
dbb7bb09 2999 ltt_event_position(tfcs->parent.e, ep);
3000 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3001 tcs->nb_event += nb_event - tfcs->saved_position;
3002 tfcs->saved_position = nb_event;
3003 }
3004 g_free(ep);
308711e5 3005
308711e5 3006 if(tcs->nb_event >= tcs->save_interval) {
3007 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3008 LTTV_STATE_SAVED_STATES);
3009 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3010 value = lttv_attribute_add(saved_states_tree,
3011 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3012 *(value.v_gobject) = (GObject *)saved_state_tree;
3013 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 3014 *(value.v_time) = self->parent.timestamp;
308711e5 3015 lttv_state_save(tcs, saved_state_tree);
3016 tcs->nb_event = 0;
08b1c66e 3017 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
80e0221b 3018 self->parent.timestamp.tv_nsec);
308711e5 3019 }
dbb7bb09 3020 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 3021 return FALSE;
3022}
eed2ef37 3023#endif //0
308711e5 3024
eed2ef37 3025#if 0
08b1c66e 3026static gboolean block_end(void *hook_data, void *call_data)
3027{
3028 LttvTracefileState *self = (LttvTracefileState *)call_data;
3029
3030 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3031
3032 LttTracefile *tf;
3033
3034 LttEventPosition *ep;
3035
3036 guint nb_block, nb_event;
3037
3038 ep = ltt_event_position_new();
3039 ltt_event_position(self->parent.e, ep);
3040 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3041 tcs->nb_event += nb_event - self->saved_position + 1;
3042 self->saved_position = 0;
3043 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3044 g_free(ep);
00e74b69 3045
3046 return FALSE;
08b1c66e 3047}
eed2ef37 3048#endif //0
3049#if 0
308711e5 3050void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3051{
3052 LttvTraceset *traceset = self->parent.ts;
3053
00e74b69 3054 guint i, j, nb_trace, nb_tracefile;
308711e5 3055
3056 LttvTraceState *ts;
3057
3058 LttvTracefileState *tfs;
3059
08b1c66e 3060 LttvTraceHook hook_start, hook_end;
308711e5 3061
3062 nb_trace = lttv_traceset_number(traceset);
3063 for(i = 0 ; i < nb_trace ; i++) {
3064 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3065
08b1c66e 3066 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3067 NULL, NULL, block_start, &hook_start);
308711e5 3068 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3069 NULL, NULL, block_end, &hook_end);
308711e5 3070
eed2ef37 3071 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3072
dbb7bb09 3073 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3074 tfs =
3075 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3076 LttvTracefileContext, j));
a5ba1787 3077 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3078 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 3079 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3080 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
eed2ef37 3081 }
3082 }
3083}
3084#endif //0
3085
3086void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3087{
3088 LttvTraceset *traceset = self->parent.ts;
3089
3090 guint i, j, nb_trace, nb_tracefile;
3091
3092 LttvTraceState *ts;
3093
3094 LttvTracefileState *tfs;
3095
3096
3097 nb_trace = lttv_traceset_number(traceset);
3098 for(i = 0 ; i < nb_trace ; i++) {
3099
3100 ts = (LttvTraceState *)self->parent.traces[i];
3101 nb_tracefile = ts->parent.tracefiles->len;
3102
ce05e187 3103 if(ts->has_precomputed_states) continue;
3104
3054461a 3105 guint *event_count = g_new(guint, 1);
3106 *event_count = 0;
3107
eed2ef37 3108 for(j = 0 ; j < nb_tracefile ; j++) {
3109 tfs =
cb03932a 3110 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3111 LttvTracefileContext*, j));
eed2ef37 3112 lttv_hooks_add(tfs->parent.event,
3113 state_save_event_hook,
3114 event_count,
3115 LTTV_PRIO_STATE);
3116
308711e5 3117 }
3118 }
14aecf75 3119
3120 lttv_process_traceset_begin(&self->parent,
3121 NULL, NULL, NULL, NULL, NULL);
3122
308711e5 3123}
3124
b56b5fec 3125gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3126{
3127 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3128
3129 lttv_state_save_add_event_hooks(tss);
3130
3131 return 0;
3132}
3133
308711e5 3134
eed2ef37 3135#if 0
308711e5 3136void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3137{
3138 LttvTraceset *traceset = self->parent.ts;
3139
00e74b69 3140 guint i, j, nb_trace, nb_tracefile;
308711e5 3141
3142 LttvTraceState *ts;
3143
3144 LttvTracefileState *tfs;
3145
08b1c66e 3146 LttvTraceHook hook_start, hook_end;
308711e5 3147
3148 nb_trace = lttv_traceset_number(traceset);
3149 for(i = 0 ; i < nb_trace ; i++) {
3150 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 3151
08b1c66e 3152 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3153 NULL, NULL, block_start, &hook_start);
08b1c66e 3154
308711e5 3155 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3156 NULL, NULL, block_end, &hook_end);
308711e5 3157
eed2ef37 3158 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3159
dbb7bb09 3160 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3161 tfs =
3162 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3163 LttvTracefileContext, j));
308711e5 3164 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3165 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 3166 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3167 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 3168 }
3169 }
3170}
eed2ef37 3171#endif //0
3172
3173void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3174{
3175 LttvTraceset *traceset = self->parent.ts;
3176
3177 guint i, j, nb_trace, nb_tracefile;
3178
3179 LttvTraceState *ts;
3180
3181 LttvTracefileState *tfs;
3182
14aecf75 3183 LttvHooks *after_trace = lttv_hooks_new();
3184
3185 lttv_hooks_add(after_trace,
3186 state_save_after_trace_hook,
3187 NULL,
3188 LTTV_PRIO_STATE);
3189
3190
3191 lttv_process_traceset_end(&self->parent,
3192 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 3193
14aecf75 3194 lttv_hooks_destroy(after_trace);
3195
eed2ef37 3196 nb_trace = lttv_traceset_number(traceset);
3197 for(i = 0 ; i < nb_trace ; i++) {
3198
3199 ts = (LttvTraceState *)self->parent.traces[i];
3200 nb_tracefile = ts->parent.tracefiles->len;
3201
ce05e187 3202 if(ts->has_precomputed_states) continue;
3203
22b165e9 3204 guint *event_count = NULL;
eed2ef37 3205
3206 for(j = 0 ; j < nb_tracefile ; j++) {
3207 tfs =
cb03932a 3208 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3209 LttvTracefileContext*, j));
eed2ef37 3210 event_count = lttv_hooks_remove(tfs->parent.event,
3211 state_save_event_hook);
eed2ef37 3212 }
22b165e9 3213 if(event_count) g_free(event_count);
eed2ef37 3214 }
3215}
308711e5 3216
b56b5fec 3217gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3218{
3219 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3220
3221 lttv_state_save_remove_event_hooks(tss);
3222
3223 return 0;
3224}
308711e5 3225
dd025f91 3226void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 3227{
3228 LttvTraceset *traceset = self->parent.ts;
3229
00e74b69 3230 guint i, nb_trace;
308711e5 3231
3232 int min_pos, mid_pos, max_pos;
3233
728d0c3e 3234 guint call_rest = 0;
3235
308711e5 3236 LttvTraceState *tcs;
3237
3238 LttvAttributeValue value;
3239
3240 LttvAttributeType type;
3241
3242 LttvAttributeName name;
3243
80e0221b 3244 gboolean is_named;
c0cb4d12 3245
308711e5 3246 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3247
d448fce2 3248 //g_tree_destroy(self->parent.pqueue);
3249 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 3250
728d0c3e 3251 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3252
308711e5 3253 nb_trace = lttv_traceset_number(traceset);
3254 for(i = 0 ; i < nb_trace ; i++) {
3255 tcs = (LttvTraceState *)self->parent.traces[i];
3256
2a2fa4f0 3257 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3258 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3259 LTTV_STATE_SAVED_STATES);
3260 min_pos = -1;
3261
3262 if(saved_states_tree) {
dd025f91 3263 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3264 mid_pos = max_pos / 2;
3265 while(min_pos < max_pos) {
c0cb4d12 3266 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
80e0221b 3267 &is_named);
dd025f91 3268 g_assert(type == LTTV_GOBJECT);
3269 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3270 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3271 &value);
3272 g_assert(type == LTTV_TIME);
3273 if(ltt_time_compare(*(value.v_time), t) < 0) {
3274 min_pos = mid_pos;
3275 closest_tree = saved_state_tree;
3276 }
3277 else max_pos = mid_pos - 1;
3278
3279 mid_pos = (min_pos + max_pos + 1) / 2;
3280 }
2a2fa4f0 3281 }
dd025f91 3282
2a2fa4f0 3283 /* restore the closest earlier saved state */
f95bc830 3284 if(min_pos != -1) {
3285 lttv_state_restore(tcs, closest_tree);
728d0c3e 3286 call_rest = 1;
f95bc830 3287 }
dd025f91 3288
2a2fa4f0 3289 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 3290 else {
3291 restore_init_state(tcs);
3292 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 3293 }
9444deae 3294 }
dd025f91 3295 /* We want to seek quickly without restoring/updating the state */
3296 else {
308711e5 3297 restore_init_state(tcs);
dd025f91 3298 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 3299 }
308711e5 3300 }
728d0c3e 3301 if(!call_rest) g_info("NOT Calling restore");
308711e5 3302}
3303
3304
3305static void
3306traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3307{
3308}
3309
3310
3311static void
3312traceset_state_finalize (LttvTracesetState *self)
3313{
3314 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3315 finalize(G_OBJECT(self));
3316}
3317
3318
3319static void
3320traceset_state_class_init (LttvTracesetContextClass *klass)
3321{
3322 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3323
3324 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3325 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3326 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3327 klass->new_traceset_context = new_traceset_context;
3328 klass->new_trace_context = new_trace_context;
3329 klass->new_tracefile_context = new_tracefile_context;
3330}
3331
3332
3333GType
3334lttv_traceset_state_get_type(void)
3335{
3336 static GType type = 0;
3337 if (type == 0) {
3338 static const GTypeInfo info = {
3339 sizeof (LttvTracesetStateClass),
3340 NULL, /* base_init */
3341 NULL, /* base_finalize */
3342 (GClassInitFunc) traceset_state_class_init, /* class_init */
3343 NULL, /* class_finalize */
3344 NULL, /* class_data */
dbb7bb09 3345 sizeof (LttvTracesetState),
308711e5 3346 0, /* n_preallocs */
00e74b69 3347 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3348 NULL /* value handling */
308711e5 3349 };
3350
3351 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3352 &info, 0);
3353 }
3354 return type;
3355}
3356
3357
3358static void
3359trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3360{
3361}
3362
3363
3364static void
3365trace_state_finalize (LttvTraceState *self)
3366{
3367 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3368 finalize(G_OBJECT(self));
3369}
3370
3371
3372static void
3373trace_state_class_init (LttvTraceStateClass *klass)
3374{
3375 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3376
3377 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3378 klass->state_save = state_save;
3379 klass->state_restore = state_restore;
3380 klass->state_saved_free = state_saved_free;
3381}
3382
3383
3384GType
3385lttv_trace_state_get_type(void)
3386{
3387 static GType type = 0;
3388 if (type == 0) {
3389 static const GTypeInfo info = {
3390 sizeof (LttvTraceStateClass),
3391 NULL, /* base_init */
3392 NULL, /* base_finalize */
3393 (GClassInitFunc) trace_state_class_init, /* class_init */
3394 NULL, /* class_finalize */
3395 NULL, /* class_data */
3396 sizeof (LttvTraceState),
3397 0, /* n_preallocs */
00e74b69 3398 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3399 NULL /* value handling */
308711e5 3400 };
3401
3402 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3403 "LttvTraceStateType", &info, 0);
3404 }
3405 return type;
3406}
3407
3408
3409static void
3410tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3411{
3412}
3413
3414
3415static void
3416tracefile_state_finalize (LttvTracefileState *self)
3417{
3418 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3419 finalize(G_OBJECT(self));
3420}
3421
3422
3423static void
3424tracefile_state_class_init (LttvTracefileStateClass *klass)
3425{
3426 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3427
3428 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3429}
3430
3431
3432GType
3433lttv_tracefile_state_get_type(void)
3434{
3435 static GType type = 0;
3436 if (type == 0) {
3437 static const GTypeInfo info = {
3438 sizeof (LttvTracefileStateClass),
3439 NULL, /* base_init */
3440 NULL, /* base_finalize */
3441 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3442 NULL, /* class_finalize */
3443 NULL, /* class_data */
3444 sizeof (LttvTracefileState),
3445 0, /* n_preallocs */
00e74b69 3446 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3447 NULL /* value handling */
308711e5 3448 };
3449
3450 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3451 "LttvTracefileStateType", &info, 0);
3452 }
3453 return type;
3454}
3455
3456
08b1c66e 3457static void module_init()
ffd54a90 3458{
83e160f2 3459 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
7b5f6cf1 3460 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
b3fd4c02 3461 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3462 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3463 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3464 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3465 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3466 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3467 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3468 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3469 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3470 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3471 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3472 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3473 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3474 LTTV_STATE_RUN = g_quark_from_string("RUN");
3475 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
80e0221b 3476 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3477 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
308711e5 3478 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3479 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3480 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 3481 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 3482 LTTV_STATE_EVENT = g_quark_from_string("event");
3483 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 3484 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 3485 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 3486 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 3487 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3488 LTTV_STATE_TRACE_STATE_USE_COUNT =
3489 g_quark_from_string("trace_state_use_count");
eed2ef37 3490
3491
3492 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 3493 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
f4b88a7d 3494 LTT_FACILITY_FS = g_quark_from_string("fs");
86c32a8f 3495 LTT_FACILITY_LIST = g_quark_from_string("list");
302efbad 3496 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
eed2ef37 3497
3498
3499 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3500 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3501 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3502 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3503 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3504 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
faf074a3 3505 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
3506 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
86c32a8f 3507 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3508 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3509 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3510 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
f63ebe51 3511 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
f4b88a7d 3512 LTT_EVENT_EXEC = g_quark_from_string("exec");
86c32a8f 3513 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
c3b3b60b 3514 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
302efbad 3515 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3516 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
7b5f6cf1 3517 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
eed2ef37 3518
3519
3520 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3521 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3522 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 3523 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
f63ebe51 3524 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3525 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3526 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
eed2ef37 3527 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3528 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3529 LTT_FIELD_PID = g_quark_from_string("pid");
fcc08e1e 3530 LTT_FIELD_TGID = g_quark_from_string("tgid");
f63ebe51 3531 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
f4b88a7d 3532 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 3533 LTT_FIELD_NAME = g_quark_from_string("name");
e62e7f3a 3534 LTT_FIELD_TYPE = g_quark_from_string("type");
b3fd4c02 3535 LTT_FIELD_MODE = g_quark_from_string("mode");
3536 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3537 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 3538 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3539 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
eed2ef37 3540
44ffb95f 3541 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3542 LTTV_CPU_IDLE = g_quark_from_string("idle");
3543 LTTV_CPU_BUSY = g_quark_from_string("busy");
598026ba 3544 LTTV_CPU_IRQ = g_quark_from_string("irq");
ffd54a90 3545}
dc877563 3546
08b1c66e 3547static void module_destroy()
ffd54a90 3548{
3549}
dc877563 3550
3551
08b1c66e 3552LTTV_MODULE("state", "State computation", \
3553 "Update the system state, possibly saving it at intervals", \
3554 module_init, module_destroy)
3555
dc877563 3556
3557
This page took 0.272169 seconds and 4 git commands to generate.