/* 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 #endif #include #include #include #include #include #include #include #include #include #include /****************************************************************************************************************************/ 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; lfac_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;ilen;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;ievent_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;ilen;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;jlen;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++;ilen;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;jlen;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;ievent_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;jlen;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;ilen;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;ilen;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");