blob: 1b7f0006e7b1fea2abb888896b889bdabbadc2f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 Dortmund University of Applied Sciences and Arts.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors: The Bao Bui
* FH Dortmund - initial API and implementation
*******************************************************************************/
package org.eclipse.app4mc.gsoc_rta;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.app4mc.amalthea.model.Amalthea;
import org.eclipse.app4mc.amalthea.model.AmaltheaServices;
import org.eclipse.app4mc.amalthea.model.ProcessingUnit;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.Task;
import org.eclipse.app4mc.amalthea.model.Time;
import org.eclipse.app4mc.amalthea.model.TimeUnit;
import org.eclipse.app4mc.amalthea.model.util.FactoryUtil;
import org.eclipse.app4mc.amalthea.model.util.SoftwareUtil;
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType;
import org.eclipse.emf.common.util.EList;
public class NPandPRTA {
private final int[] ia;
private final Amalthea model;
private final int[] preemptionTypeArray;
private boolean schedubilityCheck = true;
//Adding decimal Format for better visual checking when debugging
//ie 6000000000 ps -> 6,000,000,000 ps
private DecimalFormat df = new DecimalFormat("#,###.##");
final Logger log = LoggerFactory.getLogger(NPandPRTA.class);
boolean logDebug = log.isDebugEnabled();
boolean logInfo = log.isInfoEnabled();
boolean logError = log.isErrorEnabled();
/*
* PreemptionTypeArray will have the same length with mapping indexArray (ia), just with different value
* This will be set up when the class is initialize, the meaning of the number in array are:
* 0 = preemptive
* 1 = non-preemptive
* 2 = cooperative
*
* ia = { 5, 1, 5, 0, 1, 0, 2, 1, 2, 1, 6, 3, 4, 6 } - mapping array
* pta = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,} - the preemption type array
* this mean the first and second task of the model have non-preemption mode, the rest are preemptive
*/
public boolean isSchedubilityCheck() {
return schedubilityCheck;
}
/**Default = true.
*
* True = return result after comparing task's blocking time and period.
* False = return result as long as ultilization value is less than 100 percent.
* @param schedubilityCheck
*/
public void setSchedubilityCheck(boolean schedubilityCheck) {
this.schedubilityCheck = schedubilityCheck;
}
public NPandPRTA(final Amalthea modelp, final int[] iap) {
this.ia = iap;
this.model = modelp;
this.preemptionTypeArray = new int[iap.length];
setupPTArray();
}
/**
* Calculate classic RTA of task using this formula Ri = Ci + Sum j among HP(i)[Ri/Tj]*Cj
* https://www.it.uu.se/edu/course/homepage/realtid/ht10/schedule/Scheduling-periodic.pdf
* @param thisTask
* @param thisIA
* @return
*/
public Time getResponseTimeViaRecurrenceRelation(Task thisTask, int[] ia, final TimeType executionCase) {
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
/*Initialize variable to compare previous and current iteration in the formula*/
BigDecimal temp = BigDecimal.valueOf(2.0);
int[] thisIA = ia.clone();
CPURta rtaia = new CPURta(this.model);
List<Task> groupTaskList = groupTask(thisTask, thisIA);
List<Task> sortedTaskList = rtaia.taskSorting(groupTaskList);
/* Check ultilization value here, if ultiValue > 100% then ultiCheck = false*/
boolean ultiCheck = getUltilizationCheck(sortedTaskList, thisIA, executionCase);
if (!ultiCheck) {
//result is 0
return result;
}
int taskIndex = sortedTaskList.indexOf(thisTask);
//Loop through all task inside the list (until thisTask)
for (int i = 0; i < taskIndex + 1; i++) {
//Highest priority -> get executed first all the damn time
if (taskIndex == 0) {
if (logDebug) {
String exeTimeString = df.format(getExecutionTime(thisTask, thisIA, executionCase).getValue());
log.debug("{} ps - Task [{}] recurrence response time", exeTimeString, thisTask.getName());
}
return getExecutionTime(thisTask, thisIA, executionCase);
}
//Calculate rta by looping until the result of the previous and current are the same
else if (i == taskIndex) {
BigDecimal rZero = BigDecimal.ZERO;
/*Set up r_0 for the calculation*/
for (int j = 0; j < i + 1; j++) {
Task jTask = sortedTaskList.get(j);
Time jTaskExecutionTime = getExecutionTime(jTask, thisIA, executionCase);
BigDecimal bigDecVal = new BigDecimal(jTaskExecutionTime.getValue());
rZero = rZero.add(bigDecVal);
}
BigDecimal currentVal = rZero;
//iterate until current value = previous value
while (!temp.equals(currentVal)) {
temp = currentVal;
/**
* The iteration loop of
* Ri = Ci + Sum of all hp(i)[Ri/Tj]*Cj (round up)
* k loop are the part after the Sum symbol, after the loop we add Ci
*/
BigDecimal iteration = BigDecimal.ZERO;
for (int k = 0; k < i; k++) {
Task kTask = sortedTaskList.get(k);
Time kTaskExecutionTime = getExecutionTime(kTask, thisIA, executionCase);
Time kTaskPeriod = CommonUtils.getStimInTime(kTask);
//Need to change all time value to PS for calculation
BigInteger kTaskPeriodInPs = AmaltheaServices.convertToPicoSeconds(kTaskPeriod);
//execution time and period in bigDecimal
BigDecimal kTaskExetimeDec = new BigDecimal(kTaskExecutionTime.getValue());
BigDecimal kTaskPeriodDec = new BigDecimal(kTaskPeriodInPs);
// multiplyPart = [Ri/Tj] * Cj
// RiTj = roundupPart, Cj = kTaskExetimeDec
BigDecimal roundUpPart = currentVal.divide(kTaskPeriodDec, 0, RoundingMode.CEILING);
BigDecimal multiplyPart = roundUpPart.multiply(kTaskExetimeDec);
iteration = iteration.add(multiplyPart);
}
//Adding Ci after the iteration
Task iTask = sortedTaskList.get(i);
BigDecimal iTaskExecutionTimeDec = new BigDecimal(getExecutionTime(iTask, thisIA, executionCase).getValue());
currentVal = iteration.add(iTaskExecutionTimeDec);
}
BigDecimal thisTaskPeriodInBigDec = new BigDecimal(AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(thisTask)));
if (currentVal.compareTo(thisTaskPeriodInBigDec) > 0 && this.schedubilityCheck) {
if (logError) {
String currentValString = df.format(currentVal);
String thisTaskPeriodInBigDecString = df.format(thisTaskPeriodInBigDec);
log.error("!!! UNSCHEDULABLE !!!");
log.error("Response time of task [{}] is bigger than its period, return 0 for RT ", thisTask.getName());
log.error("{} > {}", currentValString, thisTaskPeriodInBigDecString);
}
//result is 0
return result;
}
if (logInfo) {
String currentValString = df.format(currentVal);
log.info("{} ps - Task [{}] recurrence response time", currentValString, thisTask.getName());
}
//result is currentVal calculated above
result.setValue(currentVal.toBigInteger());
}
}
return result;
}
/**
* Calculate RT of thisTask using busy window technique (level-i busy period)
* No blocking time is present here. This function is used for just simple preemptive environment case
* @param thisTask
* @param ia
* @param executionCase
* @return Time responseTime
*/
public Time getResponseTimeViaLvI(Task thisTask, int[] ia, TimeType executionCase) {
Time responseTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
int[] thisIA = ia.clone();
CPURta rtaia = new CPURta(this.model);
List<Task> groupTaskList = groupTask(thisTask, thisIA);
List<Task> sortedTaskList = rtaia.taskSorting(groupTaskList);
/* Check ultilization value here, if ultiValue > 100% then ultiCheck = false*/
boolean ultiCheck = getUltilizationCheck(sortedTaskList, thisIA, executionCase);
if (!ultiCheck) {
//result is 0
return responseTime;
}
int taskIndex = sortedTaskList.indexOf(thisTask);
Time iPeriodTime = CommonUtils.getStimInTime(thisTask);
BigInteger iPeriodInPs = AmaltheaServices.convertToPicoSeconds(iPeriodTime);
Time iExecutionTime = getExecutionTime(thisTask, thisIA, executionCase);
/* ----- Get LEVEL - I for each task ------ */
BigDecimal lv0 = BigDecimal.ZERO;
BigDecimal currentLv = BigDecimal.ONE;
BigDecimal iPeriod = new BigDecimal(iPeriodInPs);
BigDecimal iExe = new BigDecimal(iExecutionTime.getValue());
BigDecimal iResponseTime = BigDecimal.ZERO;
while (!currentLv.equals(lv0)) {
lv0 = currentLv;
//entry = each small sum of [Li/Tj]Cj, p_j >= p_i ( i = taskIndex)
BigDecimal iterationValue = BigDecimal.ZERO;
for (int entry = 0; entry < taskIndex + 1; entry++) {
Task entryTask = sortedTaskList.get(entry);
BigInteger entryPeriodInPs = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(entryTask));
BigDecimal entryPeriod = new BigDecimal(entryPeriodInPs);
BigDecimal entryExe = new BigDecimal(getExecutionTime(entryTask, thisIA, executionCase).getValue());
BigDecimal roundUp = currentLv.divide(entryPeriod, 0, RoundingMode.CEILING);
BigDecimal entryValue = roundUp.multiply(entryExe);
if (logDebug) {
String roundUpString = df.format(roundUp);
String entryValueString = df.format(entryValue);
log.debug("{} round up x {}entryValue", roundUpString, entryValueString);
}
iterationValue = iterationValue.add(entryValue);
}
currentLv = iterationValue;
}
if (logDebug) {
String lv0String = df.format(lv0);
log.debug("{} ps - level-i ", lv0String);
}
/* ----- Get K (total task iteration) ------ */
int bigK = lv0.divide(iPeriod, 0, RoundingMode.CEILING).intValue();
/* ----- Get finishing time for each task ------ */
for (int smallK = 1; smallK <= bigK; smallK++) {
log.debug(" --- k instance : {}/{} --------------------------------------------", smallK, bigK);
BigDecimal kLv = BigDecimal.ZERO;
BigDecimal currentKLv = BigDecimal.ONE;
BigDecimal kCi = iExe.multiply(BigDecimal.valueOf(smallK));
int smallK1 = smallK - 1;
int counter = 0;
while (!kLv.equals(currentKLv)) {
currentKLv = kLv;
//entry = each small sum of [Li/Tj]Cj, p_j > p_i, not >=
BigDecimal iterationValue = BigDecimal.ZERO;
for (int entry = 0; entry < taskIndex; entry++) {
Task entryTask = sortedTaskList.get(entry);
BigInteger entryPeriodInPs = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(entryTask));
BigDecimal entryPeriod = new BigDecimal(entryPeriodInPs);
BigDecimal entryExe = new BigDecimal(getExecutionTime(entryTask, thisIA, executionCase).getValue());
BigDecimal roundUp = currentKLv.divide(entryPeriod, 0, RoundingMode.CEILING);
BigDecimal entryValue = roundUp.multiply(entryExe);
iterationValue = iterationValue.add(entryValue);
if (counter == 0) {
iterationValue = BigDecimal.ZERO;
counter++;
break;
}
}
kLv = iterationValue;
kLv = kLv.add(kCi); //add k*Ci at the end of iteration
if (logDebug) {
log.debug("finishTime = iterationValue + k*Ci: ");
String s1 = df.format(iterationValue);
String s2 = df.format(kCi);
String s3 = df.format(kLv);
log.debug("{} + {} + {}", s1, s2, s3);
}
}
/* ----- Get response time for each task (k) ------ */
BigDecimal taskStartTime = iPeriod.multiply(BigDecimal.valueOf(smallK1));
if (logDebug) {
String s1 = df.format(taskStartTime);
String s2 = df.format(kLv);
log.debug("start time (k*period): {} - finishing time {}", s1, s2);
}
BigDecimal taskResponseTime = kLv.subtract(taskStartTime);
if (logDebug) {
String s1 = df.format(taskResponseTime);
log.debug("{} - this k instance response time", s1);
}
if (taskResponseTime.compareTo(iResponseTime) >= 0) {
iResponseTime = taskResponseTime;
}
if (logDebug) {
String s1 = df.format(iResponseTime);
log.debug("{} - biggest response time so far ", s1);
}
}
String taskName = thisTask.getName();
if (logInfo) {
String s1 = df.format(iResponseTime);
log.info("{} ps - Task [{}] level-i response time", s1, taskName);
}
//Check schedulability
if (iResponseTime.compareTo(iPeriod) > 0 && this.schedubilityCheck) {
log.error("!!! UNSCHEDULABLE !!!");
log.error("Response time of task [{}] is bigger than its period, return 0 for RT ", taskName);
if (logError) {
String s1 = df.format(iResponseTime);
String s2 = df.format(iPeriod);
log.error("{} > {} ", s1, s2);
}
//result is 0
return responseTime;
}
//Set response time value after all calculation above
responseTime.setValue(iResponseTime.toBigInteger());
return responseTime;
}
/**
* Calculate the execution time of longest/biggest runnable within task.
* @param thisTask
* @param ia
* @param executionCase
* @return
*/
private Time getLongestRunnableExecutionTime(Task thisTask, int[] ia, TimeType executionCase) {
//set up decimal format for debugging
DecimalFormat df = new DecimalFormat("#,###.##");
final int currentIndex = this.model.getSwModel().getTasks().indexOf(thisTask); //get index of the task in the array
final int PUI = ia[currentIndex]; // get the index of processing unit
final List<ProcessingUnit> pul = CommonUtils.getPUs(this.model);
final ProcessingUnit pu = pul.get(PUI);
//comparing value to get the longer one
Time longest = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
final List<Runnable> runnableList = SoftwareUtil.getRunnableList(thisTask, null);
RTARuntimeUtil rtautil = new RTARuntimeUtil();
//In case a task doesn't invoke any runnable, better be careful than be sorry
if (!runnableList.isEmpty()) {
for (Runnable r : runnableList) {
Time runnableTime = rtautil.getExecutionTimeForRTARunnable(r, pu, executionCase);
if (longest.compareTo(runnableTime) <= 0) {
longest = runnableTime;
}
}
}
if (runnableList.isEmpty()) {
log.error("!!!The task [{}] is doing nothing, no runnable called",thisTask.getName());
}
if (logDebug)
{
String s1 = df.format(longest.getValue());
log.debug("{} ps - Longest runnable of task [{}]", s1, thisTask.getName());
}
return longest;
}
/**
* Use when task is non-preemptive
* Calculation thisTask's response time via level-i busy window technique.
* reason is for non-preemp task, finishing time = start time + execution time.
* Response time = finishing time - period, (using k-instance)
* @param thisTask
* @param ia
* @param executionCase
* @param pTypeArray - leave null if don't use
* @boolean usePtypeArray - true if use pType array, otherwise false
* @return
*/
public Time getNonPreemptaskRTA(Task thisTask, int[] ia, TimeType executionCase, int[] pTypeArray, boolean usePtypeArray) {
//Adding decimal Format for better visual checking when debugging
//ie 6000000000 ps -> 6,000,000,000 ps
Time responseTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
//time that lp tasks may block thisTask in worst case response time
BigDecimal blockingTime = new BigDecimal(getLowerPriorityBlockingTime(thisTask, ia, executionCase, pTypeArray, usePtypeArray).getValue());
CPURta rtaia = new CPURta(this.model);
int[] thisIA = ia.clone();
List<Task> sortedTaskList = rtaia.taskSorting(groupTask(thisTask, thisIA));
/* Check ultilization value here, if ultiValue > 100% then ultiCheck = false*/
boolean ultiCheck = getUltilizationCheck(sortedTaskList, thisIA, executionCase);
if (!ultiCheck) {
//response time = 0 here, cuz the core would be damned if we use this set
return responseTime;
}
int taskIndex = sortedTaskList.indexOf(thisTask);
Time iPeriodTime = CommonUtils.getStimInTime(thisTask);
BigInteger iPeriodInPs = AmaltheaServices.convertToPicoSeconds(iPeriodTime);
Time iExecutionTime = getExecutionTime(thisTask, thisIA, executionCase);
/* ----- Get LEVEL - I for each task ------ */
BigDecimal lv0 = BigDecimal.ZERO;
BigDecimal currentLv = BigDecimal.ONE;
BigDecimal iPeriod = new BigDecimal(iPeriodInPs);
BigDecimal iExe = new BigDecimal(iExecutionTime.getValue());
BigDecimal iResponseTime = BigDecimal.ZERO;
String taskName = thisTask.getName();
/* If blocking time is equal/bigger than task period, then unschedulable for sure,
* just return 0 and warning, no need for further calculation*/
if (blockingTime.compareTo(iPeriod) >= 0 && this.schedubilityCheck) {
log.error("!!! UNSCHEDULABLE !!!");
log.error("Blocking time of task [{}] is bigger than its period, return 0 for RT ", taskName);
if (logError) {
String s1 = df.format(blockingTime);
String s2 = df.format(iPeriod);
log.error("{} > {} ", s1, s2);
}
//result is 0
return responseTime;
}
//sum of execution time of all tasks with higher prio not including this task (in TU Dortmund say included, they are imbecile )
BigDecimal hpCiSum = BigDecimal.ZERO;
int iterationCounterLvI = 0;
while (!currentLv.equals(lv0)) {
lv0 = currentLv;
//entry = each small sum of [Li/Tj]Cj, p_j >= p_i ( i = taskIndex)
BigDecimal iterationValue = BigDecimal.ZERO;
for (int entry = 0; entry < taskIndex + 1; entry++) {
Task entryTask = sortedTaskList.get(entry);
BigInteger entryPeriodInPs = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(entryTask));
BigDecimal entryPeriod = new BigDecimal(entryPeriodInPs);
BigDecimal entryExe = new BigDecimal(getExecutionTime(entryTask, thisIA, executionCase).getValue());
BigDecimal roundUp = currentLv.divide(entryPeriod, 0, RoundingMode.CEILING);
BigDecimal entryValue = roundUp.multiply(entryExe);
iterationValue = iterationValue.add(entryValue);
}
//First entry of level-i = Bi + Ci, the sum above doesn't exist (or maybe 1, not gonna risk it hence the code below)
//check non-premptive scheduler from TUDortmund pdf, google that shit
if (iterationCounterLvI == 0) {
iterationValue = iExe;
}
iterationCounterLvI++;
/* -- Add blocking for nonpreemptive here-- current lv plus blocking*/
iterationValue = iterationValue.add(blockingTime);
currentLv = iterationValue;
}
if (logDebug) {
String lv0String = df.format(lv0);
log.debug("{} ps - level-i ", lv0String);
}
/* ----- Get K (total task iteration) ------ */
int bigK = lv0.divide(iPeriod, 0, RoundingMode.CEILING).intValue();
/* ----- Get start time for each task ------ */
/**
* Things get more complicated from here, we get preemption from higher prio, blocking from lower prio
* so we have to calculate the START TIMEEEE with blocking, my man
*/
for (int smallK = 1; smallK <= bigK; smallK++) {
log.debug(" --- k instance : {}/{} --------------------------------------------", smallK, bigK);
BigDecimal kLv = BigDecimal.ZERO;
BigDecimal currentKLv = BigDecimal.ONE;
int smallK1 = smallK - 1;
BigDecimal kCi1 = iExe.multiply(BigDecimal.valueOf(smallK1));
//Equation from Tu Dortmund for this is wrong, it's < taskIndex, not < i.
for (int entry = 0; entry < taskIndex; entry++) {
Task entryTask = sortedTaskList.get(entry);
BigDecimal entryExe = new BigDecimal(getExecutionTime(entryTask, thisIA, executionCase).getValue());
hpCiSum = hpCiSum.add(entryExe);
}
int iterationCounterK = 0;
while (!kLv.equals(currentKLv)) {
currentKLv = kLv;
//entry = each small sum of [Li/Tj]Cj (rown down), j > i, not >=
BigDecimal iterationValue = BigDecimal.ZERO;
for (int entry = 0; entry < taskIndex; entry++) {
Task entryTask = sortedTaskList.get(entry);
BigInteger entryPeriodInPs = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(entryTask));
BigDecimal entryPeriod = new BigDecimal(entryPeriodInPs);
BigDecimal entryExe = new BigDecimal(getExecutionTime(entryTask, thisIA, executionCase).getValue());
BigDecimal roundDown = currentKLv.divide(entryPeriod, 0, RoundingMode.FLOOR);
BigDecimal roundDownPlusOne = roundDown.add(BigDecimal.ONE);
BigDecimal entryValue = roundDownPlusOne.multiply(entryExe);
iterationValue = iterationValue.add(entryValue);
}
kLv = iterationValue;
kLv = kLv.add(kCi1); //add k*Ci at the end of iteration
//first iteration = Bi + hpCiSum
if (iterationCounterK == 0) {
log.debug("hpCiSum - {} blocking {}", hpCiSum, blockingTime);
kLv = hpCiSum;
//reseti this for next k-task
hpCiSum = BigDecimal.ZERO;
}
log.debug("iterationValue + (k-1)*Ci + blockingtime (ignore if first iteration)");
log.debug("{} + {} + {}", iterationValue, kCi1, blockingTime);
kLv = kLv.add(blockingTime); // add blocking time here
log.debug("current iteration : {}", kLv);
iterationCounterK++;
}
/* ----- Get response time for each task (k) ------ */
BigDecimal taskStartTime = kLv;
BigDecimal taskFinishingTime = taskStartTime.add(iExe);
BigDecimal taskStartPeriod = iPeriod.multiply(BigDecimal.valueOf(smallK1));
if (logDebug) {
String s1 = df.format(taskStartTime);
String s2 = df.format(iExe);
String s3 = df.format(taskFinishingTime);
String s4 = df.format(taskStartPeriod);
log.debug("start time : {} + execution time: {} + finishing time: {}; period: {}", s1, s2, s3, s4);
}
BigDecimal taskResponseTime = taskFinishingTime.subtract(taskStartPeriod);
if (logDebug) {
String s1 = df.format(taskResponseTime);
log.debug("{} - this k instance response time ", s1);
}
if (taskResponseTime.compareTo(iResponseTime) >= 0) {
iResponseTime = taskResponseTime;
}
if (logDebug) {
String s1 = df.format(iResponseTime);
log.debug("{} - biggest response time so far ", s1);
}
}
if (logInfo) {
String s1 = df.format(iResponseTime);
log.info("{} ps - Task [{}] response time (non-preemp level-i)", s1, taskName);
}
//Check schedulability
if (iResponseTime.compareTo(iPeriod) > 0 && this.schedubilityCheck) {
log.error("!!! UNSCHEDULABLE !!!");
log.error("Response time of task [{}] is bigger than its period, return 0 for RT ", taskName);
if (logError) {
String s1 = df.format(iResponseTime);
String s2 = df.format(iPeriod);
log.error("{} > {} ", s1, s2);
}
//result is 0
return responseTime;
}
//Set response time value after all calculation above
responseTime.setValue(iResponseTime.toBigInteger());
return responseTime;
}
/**
* Calculate time that [thisTask] would be blocked by lower priority task (when lp task is non-preemptive type or cooperative type)
* @param thisTask
* @param ia
* @param executionCase
* @param pTypeArray - leave null if don't use
* @boolean usePtypeArray - true if use pType array, otherwise false
* @return Time blockingTime
*/
public Time getLowerPriorityBlockingTime(Task thisTask, int[] ia, TimeType executionCase, int[] pTypeArray, boolean usePtypeArray) {
Time blockingTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
int[] preemptiveArray;
int[] thisIA = ia.clone();
if (usePtypeArray) {
preemptiveArray = pTypeArray.clone();
}
else {
preemptiveArray = this.preemptionTypeArray.clone();
}
/*Get list of tasks that are on the same processor, then sort it from higher prio -> lower prio*/
CPURta rtaia = new CPURta(this.model);
EList<Task> listTask = this.model.getSwModel().getTasks(); //just get all the task on the list, for fun, or check it yourself below
List<Task> groupTaskList = groupTask(thisTask, thisIA);
List<Task> sortedTaskList = rtaia.taskSorting(groupTaskList);
String taskName = thisTask.getName();
if (logDebug) {
String s1 = CommonUtils.getStimInTime(thisTask).toString();
log.debug("-- get blocking time of task [{}] - period: {} ", taskName, s1);
}
/*Reverse the order from highest -> lowest to the opposite lowest -> highest,whatever in front of our index is lower priority */
Collections.reverse(sortedTaskList);
/*------------------- Get blocking time from lp task ------------------*/
/* Loop through all the task in the sorted Task list and until we see thisTask, calculate blocking time while looping,
* the longest among all blocking time will be WCBlockingTime for [thisTask]
* I have reversed the order of the task list above so we will capture all task with lower priority via top down iteration
* lowest -> highest prio
* and when we get to [thisTask], that means we have scanned all task with lower priority -> break the loop
*/
for (Task task : sortedTaskList) {
//Get out of the loop when we met thisTask in the sorted task list
//Without this, lowerPriorityTaskList will add the task with higher priority
if (task.equals(thisTask)) {
break;
}
Time tempBlockingTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
int taskIndex = listTask.indexOf(task);
int preempTypeValue = preemptiveArray[taskIndex];//listTask used to get preemptive type my dude,
String preemp = task.getPreemption().getLiteral();
Time taskPeriod = CommonUtils.getStimInTime(task);
log.debug(" checking task" + " [{}] - period {}- preemptiveType : {}", task.getName(), taskPeriod, preemp);
//If task has lower priority and is non-preemptive (preempTypeValue = 1 ), calculate that task's execution time
if (!task.equals(thisTask) && preempTypeValue == 1) {
tempBlockingTime = getExecutionTime(task, thisIA, executionCase);
if (logDebug) {
String s1 = df.format(tempBlockingTime.getValue());
String s2 = task.getName();
log.debug("{} ps - non-preemptive blocking time from task [{}]", s1, s2);
}
if (tempBlockingTime.compareTo(blockingTime) >= 0)
blockingTime = tempBlockingTime;
}
//If task has lower priority and is cooperative (preempTypeValue = 2 ), calculate the longest runnable
else if (!task.equals(thisTask) && preempTypeValue == 2) {
tempBlockingTime = getLongestRunnableExecutionTime(task, thisIA, executionCase);
if (logDebug) {
String s1 = df.format(tempBlockingTime.getValue());
String s2 = task.getName();
log.debug("{} ps - cooperative blocking time from task [{}]", s1, s2);
}
if (tempBlockingTime.compareTo(blockingTime) >= 0)
blockingTime = tempBlockingTime;
}
/* If all lower priority task are neither non-preemptive nor cooperative, blocking time = 0 (because it can only be preemptive)
* These line can be omit but meh, for a clearer picture (or messy I don't know)*/
if (tempBlockingTime.compareTo(blockingTime) >= 0)
blockingTime = tempBlockingTime;
}
if (logDebug) {
String s1 = df.format(blockingTime.getValue());
String s2 = thisTask.getName();
log.debug("{} ps - worst case blocking time of task [{}] from lower priority tasks", s1, s2);
}
return blockingTime;
}
/**
* Calculation uses classic RTA + max(max_{j of type NP and in lp(i)} C_j; max_{k of type C and in lp(i)} c_k.
* basically just add a blocking time
* (choose the longest time, task A will be block by another task (B/C/D) depends on each's execution time
* or each's runnable's execution time) among tasks within the same processor depend on each's preemption mode
* @param thisTask
* @param ia
* @param executionCase
* @return
*/
public Time getMixedPreempRTA(Task thisTask, int[] ia, TimeType executionCase) {
//Adding decimal Format for better visual checking when debugging
//ie 6000000000 ps -> 6,000,000,000 ps
DecimalFormat df = new DecimalFormat("#,###.##");
EList<Task> listTask = this.model.getSwModel().getTasks();
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
Time nonPreempBlockingTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
Time coopBlockingTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
Time taskClassicRTA = getResponseTimeViaRecurrenceRelation(thisTask, ia, executionCase);
CPURta rtaia = new CPURta(this.model);
List<Task> sortedTaskList = rtaia.taskSorting(groupTask(thisTask, ia));
//Reverse the order from highest -> lowest to the opposite lowest -> highest
Collections.reverse(sortedTaskList);
List<Task> npLowerPriorityTaskList = new ArrayList<>();
List<Task> coopLowerPriorityTaskList = new ArrayList<>();
/*Loop through all the task in the sorted Task list and add them to lowerPriorityTaskList until we see thisTask
* I have reversed the order of the task list above so we will capture all task with lower priority via top down iteration
* lowest -> highest prio
*/
for (Task task : sortedTaskList) {
int taskIndex = listTask.indexOf(task);
int preempTypeValue = this.preemptionTypeArray[taskIndex];
//add task to our list if it has lower priority and is non-preemptive (preempTypeValue = 1 )
if (!task.equals(thisTask) && preempTypeValue == 1) {
npLowerPriorityTaskList.add(task);
}
//add task to the list if has lower priority and in cooperative (preempTypeValue = 2 )
else if (!task.equals(thisTask) && preempTypeValue == 2) {
coopLowerPriorityTaskList.add(task);
}
//Get out of the loop when we met thisTask in the sorted task list
//Without this, lowerPriorityTaskList may add the task with higher priority
else if (task.equals(thisTask)) {
break;
}
}
/**
* if there is no non-preemptive task with lower priority allocate to the processor
*/
if (npLowerPriorityTaskList.isEmpty()) {
//blockingTime = 0 initially
result = result.add(nonPreempBlockingTime);
log.debug(df.format(nonPreempBlockingTime.getValue()) + " ps - Non-preemptive blocking time, no blocking");
}
/**
* if there is no cooperative task with lower priority in the same processor
*/
if (coopLowerPriorityTaskList.isEmpty()) {
//coop blocking time = 0
result = result.add(coopBlockingTime);
log.debug(df.format(coopBlockingTime.getValue()) + " ps - Cooperative blocking time, no blocking");
}
/**
* adding blocking time of lower priority task with non-preemptive mode and cooperative
* Take the longer blocking time among the 2
* Only block if there either/both task in our task lists (coop + np)
*/
if (!npLowerPriorityTaskList.isEmpty() || !coopLowerPriorityTaskList.isEmpty()) {
for (Task task : npLowerPriorityTaskList) {
int taskIndex = listTask.indexOf(task);
Time currentBlockingTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
/**
* 1 task can only have either np or coop preemption mode anyway
*/
if (this.preemptionTypeArray[taskIndex] == 1) {
currentBlockingTime = getExecutionTime(task, ia, executionCase);
}
else if (this.preemptionTypeArray[taskIndex] == 2) {
currentBlockingTime = getLongestRunnableExecutionTime(thisTask, ia, executionCase);
}
/**
* after the above we will have the time that [thisTask] is blocked by [task] potentially
* We only need to loop through all task in [listTask] to find which [task] block [thisTask] the longest
*
*/
//Compare to find the longer one when iterate
if (nonPreempBlockingTime.compareTo(currentBlockingTime) <= 0) {
nonPreempBlockingTime = currentBlockingTime;
}
log.debug(df.format(currentBlockingTime.getValue()) + " ps - Lower priority task [" + task.getName() + "] blockingTime");
}
//add blocking time when we have find the maximum execution time among
result = result.add(nonPreempBlockingTime);
log.debug(df.format(nonPreempBlockingTime.getValue()) + " ps - Final Non-preemptive/coop blocking time: ");
}
//final result should be RTA = blockingTime + classicRTA(task)
result = result.add(taskClassicRTA);
BigDecimal thisTaskPeriodInBigDec = new BigDecimal(AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(thisTask)));
if (result.getValue().compareTo(thisTaskPeriodInBigDec.toBigInteger()) > 0) {
log.error("!!! UNSCHEDULABLE !!!");
log.error("Response time of task [" + thisTask.getName() + "] is bigger than its period, return 0 for RT ");
log.error(df.format(result.getValue()) + " > " + df.format(thisTaskPeriodInBigDec));
//result is 0
result.setValue(BigInteger.ZERO);
return result;
}
log.debug(df.format(result.getValue()) + "ps - Task [" + thisTask.getName() + "] NP environment response time :");
return result;
}
/**
* this function will get PURE execution time via calculate execution time of task's runnables
* @param thisTask
* @param ia
* @return
*/
public Time getPureExecutionTime(Task thisTask, int[] ia, final TimeType executionCase) {
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
final int currentIndex = this.model.getSwModel().getTasks().indexOf(thisTask); //get index of the task in the array
final int PUI = ia[currentIndex]; // get the index of processing unit
final List<ProcessingUnit> pul = CommonUtils.getPUs(this.model);
final ProcessingUnit pu = pul.get(PUI);
RTARuntimeUtil rtautil = new RTARuntimeUtil();
/* The list of runnables of the given task */
final List<Runnable> runnableList = SoftwareUtil.getRunnableList(thisTask, null);
/*Add all execution time of runnable inside thisTask to get its PURE execution time*/
for (Runnable r : runnableList) {
Time runnableExecutionTime = rtautil.getExecutionTimeForRTARunnable(r, pu, executionCase);
result = result.add(runnableExecutionTime);
}
return result;
}
/**May sound stupid in the beginning but this will make things easier to control when
* Adding blocking/contention at the end of the function.
* @param thisTask
* @param ia
* @param executionCase
* @return
*/
private Time getExecutionTime(Task thisTask, int[] ia, final TimeType executionCase) {
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
result = result.add(getPureExecutionTime(thisTask, ia, executionCase));
/**
* Add other blocking/waiting method here if needed.
*/
return result;
}
/**
* Get core ultilization percentage by Sum all [Ci/Ti] (i = tasks in the same core)
* return false If [Ci/Ti] > 1 or ulti percentage > 100%
* groupTask = List<Task> that in the same core
* @param groupTask
* @param ia
* @param executionCase
* @return
*/
public boolean getUltilizationCheck(List<Task> groupTask, int[] ia, TimeType executionCase) {
boolean checkValue = true;
BigDecimal ultiValue = BigDecimal.ZERO;
int[] thisIA = ia.clone();
for (Task task : groupTask) {
Time taskPeriod = CommonUtils.getStimInTime(task);
Time taskExe = getExecutionTime(task, thisIA, executionCase);
BigDecimal numerator = new BigDecimal(taskExe.getValue());
BigDecimal denominator = new BigDecimal(AmaltheaServices.convertToPicoSeconds(taskPeriod));
//scale = 9 here means 9 digit after the damn commaaaaa, why scale 9? because feng shui my dude.
BigDecimal division = numerator.divide(denominator, 9, RoundingMode.HALF_UP);
ultiValue = ultiValue.add(division);
}
log.debug(ultiValue.multiply(BigDecimal.valueOf(100)) + " % - core ultilization Value ");
//if ultilization percentage > 100% then core exceed it maximum workable ability, should never happen
if (ultiValue.compareTo(BigDecimal.ONE) > 0) {
log.error("!!! UNSCHEDULABLE !!!");
log.error("Ultilization value :" + ultiValue.multiply(BigDecimal.valueOf(100)) + " exceed 100% ");
checkValue = false;
}
return checkValue;
}
/**
* Initialize preemptive array.
*/
private void setupPTArray() {
log.debug("Initialize class NPandPRTA");
EList<Task> listTask = this.model.getSwModel().getTasks();
for (Task task : listTask) {
int taskIndex = listTask.indexOf(task);
String preemp = task.getPreemption().getLiteral();
if (preemp.matches("preemptive")) {
this.preemptionTypeArray[taskIndex] = 0;
}
else if (preemp.matches("non_preemptive")) {
this.preemptionTypeArray[taskIndex] = 1;
}
else if (preemp.matches("cooperative")) {
this.preemptionTypeArray[taskIndex] = 2;
}
}
if (logDebug)
{
String s1 = Arrays.toString(this.ia);
String s2 = Arrays.toString(this.preemptionTypeArray) ;
log.debug("{} - ia", s1);
log.debug("{} - pta",s2);
}
}
private List<Task> groupTask(final Task thisTask, int[] ia) {
final List<Task> stepOneTaskList = new ArrayList<>();
final EList<Task> taskList = this.model.getSwModel().getTasks();
final int currentIndex = this.model.getSwModel().getTasks().indexOf(thisTask);
CPURta rtaia = new CPURta(this.model);
final int PUI = ia[currentIndex];
for (int i = 0; i < ia.length; i++) {
if (PUI == ia[i]) {
stepOneTaskList.add(taskList.get(i));
}
}
return rtaia.taskSorting(stepOneTaskList);
}
}