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