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