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