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