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