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