--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <lttv/module.h>
+#include <lttv/xenoltt_sim.h>
+#include <lttv/stats.h>
+#include <lttv/lttv.h>
+#include <lttv/attribute.h>
+#include <ltt/facility.h>
+#include <ltt/trace.h>
+#include <ltt/event.h>
+#include <ltt/type.h>
+
+
+/****************************************************************************************************************************/
+gboolean save_event(void *hook_data, void *call_data);
+/****************************************************************************************************************************/
+
+gboolean sim_every_event(void *hook_data, void *call_data)
+{
+ LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
+
+ LttEvent *e = ltt_tracefile_get_event(tfcs->parent.parent.tf);
+
+ LttvAttributeValue v;
+
+ /* The current branch corresponds to the tracefile/process/interrupt state.
+ Statistics are added within it, to count the number of events of this
+ type occuring in this context. A quark has been pre-allocated for each
+ event type and is used as name. */
+
+ lttv_attribute_find(tfcs->current_event_types_tree,
+ ltt_eventtype_name(ltt_event_eventtype(e)),
+ LTTV_UINT, &v);
+ (*(v.v_uint))++;
+ return FALSE;
+}
+
+// Hook wrapper. call_data is a traceset context.
+gboolean lttv_xenoltt_sim_hook_add_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
+
+ thread_event_list = g_array_new(FALSE, FALSE, sizeof(ThreadEventData*));
+ running_thread = g_array_new(FALSE, FALSE, sizeof(RunningThread*));
+
+ lttv_xenoltt_sim_add_event_hooks(tss);
+
+ return 0;
+}
+
+void lttv_xenoltt_sim_add_event_hooks(LttvTracesetStats *self)
+{
+ LttvTraceset *traceset = self->parent.parent.ts;
+
+ guint i, j, k, l, nb_trace, nb_tracefile;
+
+ LttvTraceStats *ts;
+
+ LttvTracefileStats *tfs;
+
+ GArray *hooks, *before_hooks;
+
+ LttvTraceHook *hook;
+
+ LttvTraceHookByFacility *thf;
+
+ LttvAttributeValue val;
+
+ gint ret;
+ gint hn;
+
+ nb_trace = lttv_traceset_number(traceset);
+ for(i = 0 ; i < nb_trace ; i++) {
+ ts = (LttvTraceStats *)self->parent.parent.traces[i];
+
+ /* Find the eventtype id for the following events and register the
+ associated by id hooks. */
+
+ hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 16);
+ g_array_set_size(hooks, 16);
+ hn=0;
+ /*
+ LTT_EVENT_XENOLTT_THREAD_INIT,
+ LTT_EVENT_XENOLTT_THREAD_SET_PERIOD,
+ LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD,
+ LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD,
+ LTT_EVENT_XENOLTT_THREAD_SUSPEND,
+ LTT_EVENT_XENOLTT_THREAD_START,
+ LTT_EVENT_XENOLTT_THREAD_RESUME,
+ LTT_EVENT_XENOLTT_THREAD_DELETE,
+ LTT_EVENT_XENOLTT_THREAD_UNBLOCK,
+ LTT_EVENT_XENOLTT_THREAD_RENICE,
+ LTT_EVENT_XENOLTT_TIMER_TICK,
+ LTT_EVENT_XENOLTT_SYNCH_SET_OWNER,
+ LTT_EVENT_XENOLTT_SYNCH_UNLOCK,
+ LTT_EVENT_XENOLTT_SYNCH_WAKEUP1,
+ LTT_EVENT_XENOLTT_SYNCH_WAKEUPX,
+ LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON,
+ LTT_EVENT_XENOLTT_SYNCH_FLUSH,
+ LTT_EVENT_XENOLTT_SYNCH_FORGET,
+ LTT_EVENT_XENOLTT_THREAD_SWITCH;
+ */
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_INIT,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SET_PERIOD,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SUSPEND,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_START,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_RESUME,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_DELETE,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SWITCH,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_THREAD_SWITCH,
+ LTT_FIELD_XENOLTT_ADDRESS_OUT, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ ret = lttv_trace_find_hook(ts->parent.parent.t,
+ LTT_FACILITY_XENOLTT, LTT_EVENT_XENOLTT_TIMER_TICK,
+ LTT_FIELD_XENOLTT_ADDRESS, 0, 0,
+ save_event, NULL,
+ &g_array_index(hooks, LttvTraceHook, hn++));
+ if(ret) hn--;
+
+ g_array_set_size(hooks, hn);
+
+ before_hooks = hooks;
+
+ /* Add these hooks to each event_by_id hooks list */
+
+ nb_tracefile = ts->parent.parent.tracefiles->len;
+
+ for(j = 0 ; j < nb_tracefile ; j++) {
+ tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
+ LttvTracefileContext*, j));
+ lttv_hooks_add(tfs->parent.parent.event, sim_every_event, NULL,
+ LTTV_PRIO_DEFAULT);
+
+ for(k = 0 ; k < before_hooks->len ; k++) {
+ hook = &g_array_index(before_hooks, LttvTraceHook, k);
+ for(l = 0; l<hook->fac_list->len;l++) {
+ thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
+ lttv_hooks_add(
+ lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
+ thf->h,
+ thf,
+ LTTV_PRIO_DEFAULT);
+ }
+ }
+
+ }
+ lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
+ LTTV_POINTER, &val);
+ *(val.v_pointer) = before_hooks;
+ }
+}
+
+// Hook wrapper. call_data is a traceset context.
+gboolean lttv_xenoltt_sim_hook_remove_event_hooks(void *hook_data, void *call_data)
+{
+ LttvTracesetStats *tss = (LttvTracesetStats*)call_data;
+
+ lttv_xenoltt_sim_remove_event_hooks(tss);
+
+ return 0;
+}
+
+void lttv_xenoltt_sim_remove_event_hooks(LttvTracesetStats *self)
+{
+ LttvTraceset *traceset = self->parent.parent.ts;
+
+ guint i, j, k, l, nb_trace, nb_tracefile;
+
+ LttvTraceStats *ts;
+
+ LttvTracefileStats *tfs;
+
+ GArray *before_hooks;
+
+ LttvTraceHook *hook;
+
+ LttvTraceHookByFacility *thf;
+
+ LttvAttributeValue val;
+
+ nb_trace = lttv_traceset_number(traceset);
+ for(i = 0 ; i < nb_trace ; i++) {
+ ts = (LttvTraceStats*)self->parent.parent.traces[i];
+ lttv_attribute_find(self->parent.parent.a, LTTV_STATS_BEFORE_HOOKS,
+ LTTV_POINTER, &val);
+ before_hooks = *(val.v_pointer);
+
+ /* Remove these hooks from each event_by_id hooks list */
+
+ nb_tracefile = ts->parent.parent.tracefiles->len;
+
+ for(j = 0 ; j < nb_tracefile ; j++) {
+ tfs = LTTV_TRACEFILE_STATS(g_array_index(ts->parent.parent.tracefiles,
+ LttvTracefileContext*, j));
+ lttv_hooks_remove_data(tfs->parent.parent.event, sim_every_event,
+ NULL);
+
+ for(k = 0 ; k < before_hooks->len ; k++) {
+ hook = &g_array_index(before_hooks, LttvTraceHook, k);
+ for(l = 0 ; l < hook->fac_list->len ; l++) {
+ thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
+ lttv_hooks_remove_data(
+ lttv_hooks_by_id_find(tfs->parent.parent.event_by_id, thf->id),
+ thf->h,
+ thf);
+ }
+ }
+ }
+ g_debug("lttv_stats_remove_event_hooks()");
+ g_array_free(before_hooks, TRUE);
+ }
+}
+
+
+
+/****************************************************************************************************************************/
+
+
+
+/*
+ This function will look into the thread list to find the corresponding thread and returns it
+ This way we will be able to add a new event to this thread events list.
+*/
+ThreadEventData* lookup_or_create_thread(gulong address, guint prio, LttTime creation_time, GQuark name){
+ printf("lookup_or_create\n");
+ int i, index = 0;
+ ThreadEventData *temp_thread;
+ ThreadEventData *temp_thread_2 = g_new(ThreadEventData, 1);
+ temp_thread_2->address = address;
+ temp_thread_2->prio = prio;
+ temp_thread_2->creation_time = creation_time;
+ temp_thread_2->name = name;
+ temp_thread_2->event_list = g_array_new(FALSE, FALSE, sizeof(EventData*));
+
+
+ for(i=0;i<thread_event_list->len;i++){
+ temp_thread = g_array_index(thread_event_list, ThreadEventData*, i);
+ if (temp_thread->address == temp_thread_2->address &&
+ ltt_time_compare(temp_thread->creation_time,temp_thread_2->creation_time) == 0)
+ return temp_thread; // Thread is found we return it
+ /* Otherwise we check for the priority, this will help us to defined the
+ index where to insert the thread. This way we don't to sort the thread list */
+ else if(temp_thread_2->prio <= temp_thread->prio) index++;
+ }
+
+ g_array_insert_val(thread_event_list,index,temp_thread_2);
+
+ return temp_thread_2; // New inserted thread is returned
+}
+
+void calculate_event_time(guint index, ThreadEventData *temp_thread){
+ LttTime next_tick = ltt_time_zero, delay, preempt_begin, preempt_time,
+ last_write_event_time, last_read_event_time, original_event_time;
+ EventData *new_event, *event;
+ int i,j, overruns = 0;
+ gboolean wait_period_called = FALSE;
+ RunningThread *temp_running_thread;
+ GArray* new_event_list = g_array_new(FALSE, FALSE, sizeof(EventData*));
+ gboolean first_thread_switch, running = FALSE;
+ LttTime new_period = { 0, temp_thread->period };
+
+ // We will iterate on all event of this thread
+ for(i=0;i<temp_thread->event_list->len;i++){
+ // for the first event read
+ if (i == 0){
+ new_event = g_array_index(temp_thread->event_list, EventData*, i);
+ last_write_event_time = new_event->event_time;
+ last_read_event_time = new_event->event_time;
+ original_event_time = new_event->event_time;
+ }
+ else{
+ last_write_event_time = new_event->event_time;
+ last_read_event_time = original_event_time;
+ new_event = g_array_index(temp_thread->event_list, EventData*, i);
+ original_event_time = new_event->event_time;
+ }
+
+ // Calculate the delay between to following events
+ delay = ltt_time_sub(original_event_time,last_read_event_time);
+
+ // We need to save all events from the timer_tick until the wait_period event
+ // At the same time we can calculate the new time of the event
+ if (new_event->name == LTT_EVENT_XENOLTT_TIMER_TICK){
+ printf("NEW PERIOD\n");
+ // The first tick will be unchanged
+ if(ltt_time_compare(ltt_time_zero,next_tick) != 0){
+ new_event->event_time = next_tick;
+ }
+ next_tick = ltt_time_add(new_event->event_time,new_period);
+ wait_period_called = FALSE; // We prepare for next period that should begin now
+
+ g_array_append_val(new_event_list,new_event); // insert the new timer_tick
+ printf("\tTIMER_TICK - TIME: %lu.%lu - %lu.%lu\n", original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+
+ first_thread_switch = TRUE;
+ preempt_time = ltt_time_zero;
+ preempt_begin = ltt_time_zero;
+
+ /************************************************************************
+ * Beginning of a new period
+ * We must check for thread_switching (preemption)
+ * new timer tick to create
+ * overrun to create
+ * event missed_period to create
+ ************************************************************************/
+
+ while(new_event->name != LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD){ // Until the end of the period
+ i++;
+ last_write_event_time = new_event->event_time;
+ last_read_event_time = original_event_time;
+ new_event = g_array_index(temp_thread->event_list, EventData*, i);
+ original_event_time = new_event->event_time;
+
+ // Calculate the delay between to following events
+ delay = ltt_time_sub(original_event_time,last_read_event_time);
+ delay = ltt_time_sub(delay,preempt_time);
+
+ // Need to test if we have exceeded the new period
+ if(new_event->name != LTT_EVENT_XENOLTT_TIMER_TICK){
+ if (ltt_time_compare(ltt_time_add(last_write_event_time,delay),next_tick) > 0){
+ EventData *tick_event = g_new(EventData, 1);
+ tick_event->event_time = next_tick;
+ tick_event->name = LTT_EVENT_XENOLTT_TIMER_TICK;
+ g_array_append_val(new_event_list,tick_event);
+ next_tick = ltt_time_add(tick_event->event_time,new_period);
+ printf("\t%s - TIME: \t%lu.%lu\n", g_quark_to_string(tick_event->name),tick_event->event_time.tv_sec,tick_event->event_time.tv_nsec);
+ overruns++;
+ }
+ }
+
+ if(new_event->name == LTT_EVENT_XENOLTT_THREAD_INIT ||
+ new_event->name == LTT_EVENT_XENOLTT_THREAD_SET_PERIOD ||
+ new_event->name == LTT_EVENT_XENOLTT_THREAD_START ||
+ new_event->name == LTT_EVENT_XENOLTT_THREAD_RESUME ||
+ new_event->name == LTT_EVENT_XENOLTT_THREAD_RENICE ||
+ new_event->name == LTT_EVENT_XENOLTT_THREAD_SUSPEND){
+ new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event
+ // Insert event in the period list
+ g_array_append_val(new_event_list,new_event);
+ printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ }
+ // the first Thread_Switch indicate that the thread is now running
+ else if(new_event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){
+ if (first_thread_switch){
+ running = TRUE;
+ first_thread_switch = FALSE;
+ new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event
+ // Insert event in the period list
+ g_array_append_val(new_event_list,new_event);
+ printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ }
+ // Not the first thread switch, we will delete this event and the previous one that should be thread_suspend
+ else if(running){
+ running = FALSE; // Stop the thread
+ new_event = g_array_index(temp_thread->event_list, EventData*, (i-1));
+ preempt_begin = new_event->event_time;// Save the time of the preemption (time of the suspend event
+ }
+ // Thread is suspended and want to restart, delete the thread_switch and the following event that should be thread_resume
+ else{
+ running = TRUE; // restart thread
+ i++;
+ new_event = g_array_index(temp_thread->event_list, EventData*, i);
+ preempt_time = ltt_time_add(preempt_time,ltt_time_sub(new_event->event_time,preempt_begin));// ignore the time spent in ready state
+ }
+ }
+ // Thread going in overrun
+ else if(new_event->name == LTT_EVENT_XENOLTT_TIMER_TICK){
+ new_event->event_time = next_tick;
+ next_tick = ltt_time_add(new_event->event_time,new_period);
+ overruns++; // If wait_period has not been called, this means we are going in overrun
+ // Insert event in the period list
+ g_array_append_val(new_event_list,new_event);
+ printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ }
+
+ if(new_event->name == LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD){
+ new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event
+ g_array_append_val(new_event_list,new_event);
+ printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ printf("END PERIOD\n");
+ wait_period_called = TRUE;
+ if(overruns > 0){
+ EventData *missed_period_event = g_new(EventData, 1);
+ missed_period_event->event_time = new_event->event_time; // Same time ??
+ missed_period_event->name = LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD;
+ g_array_append_val(new_event_list,missed_period_event);
+ printf("\t%s - TIME: %lu.%lu\n", g_quark_to_string(missed_period_event->name),
+ missed_period_event->event_time.tv_sec,missed_period_event->event_time.tv_nsec);
+ }
+ overruns = 0;
+ // Period is finished
+ running = FALSE;
+ }
+
+ if(new_event->name == LTT_EVENT_XENOLTT_THREAD_DELETE){
+ // Insert event in the period list
+ new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event
+ g_array_append_val(new_event_list,new_event);
+ printf("\t%s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ break;
+ }
+ }
+ }
+ // For other events, simply save them with new time
+ else{
+ if (new_event->name != LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD){
+ new_event->event_time = ltt_time_add(last_write_event_time,delay); // New time of the event
+ g_array_append_val(new_event_list,new_event);
+ printf("NO_PERIOD %s - TIME: %lu.%lu - %lu.%lu\n", g_quark_to_string(new_event->name),original_event_time.tv_sec,original_event_time.tv_nsec,
+ new_event->event_time.tv_sec,new_event->event_time.tv_nsec);
+ }
+ }
+ }
+
+ // Now we have a full list of events representing the simulation of the current task
+ // Last step consist of checking if this thread will be preempted by others
+ // To see that, we will check in the running_thread list to find some free time space
+
+ // Iterate on the event_list and check for every thread_switch
+ // We will iterate on all event of this thread
+ gboolean not_running = TRUE;
+
+ for(i=0;i<new_event_list->len;i++){
+ event = g_array_index(new_event_list, EventData*, i);
+ if (event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){
+ if (not_running){
+ not_running = FALSE;
+ for(j=0;j<running_thread->len;j++){
+ temp_running_thread = g_array_index(running_thread, RunningThread*, j);
+ // First we need to get the thread running at the closest time before the current time
+ if (ltt_time_compare(temp_running_thread->begin_time,event->event_time) > 0){
+ // If thread finishes after current time, we must delay the task
+ // We will check the previous thread in the running list
+ temp_running_thread = g_array_index(running_thread, RunningThread*, (j-1));
+ if (ltt_time_compare(temp_running_thread->end_time,event->event_time) <= 0){
+ event->event_time = temp_running_thread->end_time;
+ }
+ else{ // Time is good
+ break;
+ }
+ }
+ }
+
+
+ // At this time we should have found a free starting position
+ RunningThread *new_running = g_new(RunningThread,1);
+ new_running->thread = temp_thread;
+ new_running->begin_time = event->event_time;
+
+ j--;
+
+ delay = ltt_time_zero;
+ // Next step is to chek before all event, if we must preempt the thread because a higher priority task is already running
+ // Preemption will cause the creation of 2 events thread_switch
+ for(i++;i<new_event_list->len;i++){
+ event = g_array_index(new_event_list, EventData*, i);
+ // Don't delay Timer_Tick
+ if (event->name == LTT_EVENT_XENOLTT_TIMER_TICK){
+ if (wait_period_called) wait_period_called = FALSE;
+ }
+ // If event is a thread_switch, this means we have finish the period
+ else if (event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){
+ event->event_time = ltt_time_add(event->event_time,delay);
+ new_running->end_time = event->event_time;
+ // Add the thread in the running thread list
+ // j is the index where we found a free time space
+ g_array_insert_val(running_thread,j,new_running);
+ not_running = TRUE;
+ break;
+ }
+ else{
+ event->event_time = ltt_time_add(event->event_time,delay);
+
+ // We must check the if the next running thread is beginning before the event_time
+ temp_running_thread = g_array_index(running_thread, RunningThread*, j);
+
+ if(ltt_time_compare(event->event_time,temp_running_thread->begin_time) >= 0){
+ // if so, we must preempt the task and delay all event of the period
+ delay = ltt_time_add(delay,ltt_time_sub(event->event_time,temp_running_thread->begin_time));
+
+ // Insert a thread switch out
+ new_event = g_new(EventData, 1);
+ new_event->event_time = temp_running_thread->begin_time;
+ new_event->name = LTT_EVENT_XENOLTT_THREAD_SWITCH;
+ g_array_insert_val(new_event_list,i,new_event);
+
+ // Insert a thread switch in that will be check at next iteration
+ new_event = g_new(EventData, 1);
+ new_event->event_time = temp_running_thread->end_time;
+ new_event->name = LTT_EVENT_XENOLTT_THREAD_SWITCH;
+ g_array_insert_val(new_event_list,(i+1),new_event);
+
+ // Insert the thread in the running thread
+ new_running->end_time = temp_running_thread->begin_time;
+ g_array_insert_val(running_thread,j,new_running);
+ not_running = TRUE;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+/*
+ //Print the new thread simulation
+ for(j=0;j<new_event_list->len;j++){
+ event = g_array_index(new_event_list, EventData*, j);
+ printf("%s - TIME: %lu.%lu\n", g_quark_to_string(event->name),event->event_time.tv_sec,event->event_time.tv_nsec);
+ }
+*/
+}
+
+void simulater_high_priority_thread(ThreadEventData* thread){
+ EventData *event;
+ gboolean running = FALSE;
+ RunningThread *run_thread = g_new(RunningThread, 1);
+ RunningThread *temp_thread;
+ int i,j;
+ LttTime begin_time = ltt_time_zero;
+ LttTime end_time = ltt_time_zero;
+ gboolean inserted;
+
+ for(i=0;i<thread->event_list->len;i++){
+ event = g_array_index(thread->event_list, EventData*, i);
+
+ if(event->name == LTT_EVENT_XENOLTT_THREAD_SWITCH){
+ if(running){
+ running = FALSE;
+ end_time = event->event_time;
+ run_thread = g_new(RunningThread, 1);
+ run_thread->thread = thread;
+ run_thread->begin_time = begin_time;
+ run_thread->end_time = end_time;
+
+ inserted = FALSE;
+ for(j=0;j<running_thread->len;j++){
+ temp_thread = g_array_index(running_thread, RunningThread*, j);
+ if (ltt_time_compare(temp_thread->begin_time,run_thread->begin_time) > 0){
+ g_array_insert_val(running_thread,j,run_thread);
+ inserted = TRUE;
+ break;
+ }
+ }
+ if (!inserted) g_array_append_val(running_thread,run_thread);
+ }
+ else{
+ running = TRUE;
+ begin_time = event->event_time;
+ }
+ }
+
+
+ }
+}
+
+gint sort_running_thread(gconstpointer a,gconstpointer b){
+ const RunningThread *pa = (const RunningThread*)a;
+ const RunningThread *pb = (const RunningThread*)b;
+
+ return ltt_time_compare(pa->begin_time,pb->begin_time);
+}
+
+void compute_simulation(guint index,guint period){
+
+ int i;
+ ThreadEventData *temp_thread;
+ RunningThread *run_thread;
+
+ printf("---\n");
+
+ printf("-> %u\n",thread_event_list->len);
+ // First, set the new period of the thread
+ temp_thread = g_array_index(thread_event_list, ThreadEventData*, index);
+ // We will double the simulation only if period has changed
+ if (period != temp_thread->period) temp_thread->period = period;
+ else{
+ printf("Period is the same, no need to simulate\n");
+ return;
+ }
+
+ /*
+ First, we need to ignore all task with higher priority
+ than the task we want to simulate that's why we begin the simulation
+ from the thread index which we will modify the period
+ */
+ printf("simulater_high_priority_thread\n");
+ for(i=0;i<index;i++){
+ temp_thread = g_array_index(thread_event_list, ThreadEventData*, i);
+ simulater_high_priority_thread(temp_thread);
+ }
+
+ for(i=index;i<thread_event_list->len;i++){
+ temp_thread = g_array_index(thread_event_list, ThreadEventData*, i);
+ printf("%s - %u\n",g_quark_to_string(temp_thread->name), temp_thread->prio);
+
+
+// temp_thread->period = period;
+ temp_thread->period = 20000;
+
+
+ // We will simulate this thread considering all higher priority threads
+ printf("calculate_event_time\n");
+ calculate_event_time(index, temp_thread);
+ }
+
+
+ printf("print run_thread\n");
+ for(i=0;i<running_thread->len;i++){
+ run_thread = g_array_index(running_thread, RunningThread*, i);
+ printf("%s\tFROM:%lu.%lu\tTO:%lu.%lu\n",g_quark_to_string(run_thread->thread->name),run_thread->begin_time.tv_sec,run_thread->begin_time.tv_nsec,
+ run_thread->end_time.tv_sec,run_thread->end_time.tv_nsec);
+ }
+}
+
+gboolean save_event(void *hook_data, void *call_data){
+ LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
+ LttvTracefileStats *tfcs = (LttvTracefileStats *)call_data;
+ LttvTraceState *ts = (LttvTraceState*)tfcs->parent.parent.t_context;
+ guint cpu = tfcs->parent.cpu;
+ LttvXenoThreadState *thread_info;
+
+ LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
+ LttEvent *e = ltt_tracefile_get_event(tfc->tf);
+ GQuark event_name = ltt_eventtype_name(ltt_event_eventtype(e));
+ LttTime evtime = ltt_event_time(e);
+
+ if (event_name == LTT_EVENT_XENOLTT_TIMER_TICK){
+ gulong timer_address = ltt_event_get_long_unsigned(e, thf->f1);
+ thread_info = lttv_xeno_state_find_thread_from_timer(ts,cpu,timer_address);
+ }
+ else{
+ gulong address = ltt_event_get_long_unsigned(e, thf->f1);
+ // First we need to lookup for the current thread in the list
+ thread_info = lttv_xeno_state_find_thread(ts,cpu,address);
+ }
+
+ if (thread_info != NULL){
+ ThreadEventData *thread = lookup_or_create_thread(thread_info->address, thread_info->prio, thread_info->creation_time, thread_info->name);
+ // printf("%s - %lu.%lu\n",g_quark_to_string(event_name), evtime.tv_sec, evtime.tv_nsec);
+ if (event_name == LTT_EVENT_XENOLTT_THREAD_SET_PERIOD) thread->period = thread_info->period;
+ //Thread is found in the table, we can insert the new event in the list
+ EventData *new_event = g_new(EventData, 1);
+ new_event->event_time = evtime;
+ new_event->name = event_name;
+ new_event->event = e;
+ g_array_append_val(thread->event_list,new_event);
+ }
+
+ return FALSE;
+}
+
+/****************************************************************************************************************************/
+
+
+
+
+static void module_init()
+{
+}
+
+static void module_destroy()
+{
+}
+
+
+LTTV_MODULE("xenoltt_sim", "Compute Xenomai Tasks simulation", \
+ "Simulate a task execution with a different period", \
+ module_init, module_destroy, "state");