blob: 055ecd835d94251842885ef51eb4c15ed8142cfe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 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:
* FH Dortmund - initial API and implementation
*******************************************************************************/
package org.eclipse.app4mc.gsoc_rta;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.eclipse.app4mc.amalthea.model.AmaltheaServices;
import org.eclipse.app4mc.amalthea.model.Event;
import org.eclipse.app4mc.amalthea.model.EventChain;
import org.eclipse.app4mc.amalthea.model.EventChainContainer;
import org.eclipse.app4mc.amalthea.model.EventChainItem;
import org.eclipse.app4mc.amalthea.model.Label;
import org.eclipse.app4mc.amalthea.model.ProcessEvent;
import org.eclipse.app4mc.amalthea.model.ProcessingUnit;
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.io.AmaltheaLoader;
import org.eclipse.app4mc.amalthea.model.util.FactoryUtil;
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType;
import org.eclipse.app4mc.amalthea.model.util.SoftwareUtil;
import org.eclipse.app4mc.gsoc_rta.SharedConsts.ComParadigm;
import org.eclipse.emf.common.util.EList;
/**
* Date: August 21-2019
* @author Junhyung Ki
* @version 1.0
* This class is to analyze End-to-End latency with the help of CPURta class.
*/
public class E2ELatency {
public final File inputFile = new File("model-input/WATERS19_release/ChallengeModel_release.amxmi");
public CPURta cpurta = new CPURta();
public static final int[] defaultIAMapping = new int[] { 4, 1, 1, 3, 4, 0, 3, 3, 3, 0, 6, 2, 5, 6 };
public static void main(String[] args) {
org.apache.log4j.BasicConfigurator.configure();
Logger.getRootLogger().setLevel(Level.ERROR);
final E2ELatency ecl = new E2ELatency();
ecl.run();
}
public void run() {
final Logger log = Logger.getLogger(E2ELatency.class);
this.setCPURta(this.cpurta);
if (this.cpurta.getModel() == null) {
log.debug("Model is empty. Please check the model path.");
return ;
}
final EList<EventChain> ecList = this.cpurta.getModel().getConstraintsModel().getEventChains();
for (int i = 0; i < ecList.size(); i++) {
log.debug(" ----- " + "Chain " + (i+1) + " ----- ");
log.debug("Best-case Task-Chain Reaction(Direct): " + this.getTCReactionBC(ecList.get(i), ComParadigm.DIRECT, this.cpurta));
log.debug("Worst-case Task-Chain Reaction(Direct): " + this.getTCReactionWC(ecList.get(i), ComParadigm.DIRECT, this.cpurta));
log.debug("Best-case Task-Chain Reaction(Implicit): " + this.getTCReactionBC(ecList.get(i), ComParadigm.IMPLICIT, this.cpurta));
log.debug("Worst-case Task-Chain Reaction(Implicit): " + this.getTCReactionWC(ecList.get(i), ComParadigm.IMPLICIT, this.cpurta));
log.debug("Best-case Task-Chain Reaction(LET): " + this.getLetReactionBC(ecList.get(i), this.cpurta));
log.debug("Worst-case Task-Chain Reaction(LET): " + this.getLetReactionWC(ecList.get(i), this.cpurta));
log.debug("Worst-case Task-Chain Age(Direct): " + this.getTaskChainAge(ecList.get(i), TimeType.WCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Best-case Task-Chain Age(Direct): " + this.getTaskChainAge(ecList.get(i), TimeType.BCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Worst-case Task-Chain Age(Implicit): " + this.getTaskChainAge(ecList.get(i), TimeType.WCET, ComParadigm.IMPLICIT, this.cpurta));
log.debug("Best-case Task-Chain Age(Implicit): " + this.getTaskChainAge(ecList.get(i), TimeType.BCET, ComParadigm.IMPLICIT, this.cpurta));
log.debug("Worst-case Early Reaction(Direct): " + this.getEarlyReaction(ecList.get(i), TimeType.WCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Best-case Early Reaction(Direct): " + this.getEarlyReaction(ecList.get(i), TimeType.BCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Worst-case Early Reaction(Implicit): " + this.getEarlyReaction(ecList.get(i), TimeType.WCET, ComParadigm.IMPLICIT, this.cpurta));
log.debug("Best-case Early Reaction(Implicit): " + this.getEarlyReaction(ecList.get(i), TimeType.BCET, ComParadigm.IMPLICIT, this.cpurta));
log.debug("\n");
}
log.debug("\n################################################################################################################\n");
for (int i = 0; i < ecList.size(); i++) {
log.debug(" ----- " + "Chain " + (i+1) + " ----- ");
for (int j = 0; j < this.cpurta.getModel().getSwModel().getLabels().size(); j++) {
final Label label = this.cpurta.getModel().getSwModel().getLabels().get(j);
log.debug("***** " + label.getName() + " *****");
log.debug("Worst-case Data Age(Direct): " + this.getDataAge(label, ecList.get(i), TimeType.WCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Best-case Data Age(Direct): " + this.getDataAge(label, ecList.get(i), TimeType.BCET, ComParadigm.DIRECT, this.cpurta));
log.debug("Worst-case Data Age(Implicit): " + this.getDataAge(label, ecList.get(i), TimeType.WCET, ComParadigm.IMPLICIT, this.cpurta));
log.debug("Best-case Data Age(Implicit): " + this.getDataAge(label, ecList.get(i), TimeType.BCET, ComParadigm.IMPLICIT, this.cpurta) + "\n");
}
log.debug("\n");
}
}
/**
* Set CPURta class
* @param cpurta the instance of CPURta class
*/
public void setCPURta(final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
cpurta.setModel(AmaltheaLoader.loadFromFile(this.inputFile));
if (cpurta.getModel() == null) {
log.debug("Model is empty. Please check the model path.");
return ;
}
cpurta.setTRT(cpurta.getDefaultTRT(cpurta.getModel()));
cpurta.setIA(defaultIAMapping);
cpurta.setPUl(CommonUtils.getPUs(cpurta.getModel()));
cpurta.setContention(cpurta.getIA(), cpurta.getModel());
}
/**
* Check the readiness of the observed class instance
* @param cpurta the instance of CPURta class
* @return
* boolean value that indicates whether cpurta instance is ready
*/
private boolean isTheRTAClassReady(final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
if (cpurta.getModel() == null) {
log.debug("Model Setting needs to be done for cpurta!");
return false;
} else if (cpurta.getTRT() == null) {
log.debug("TRT Setting needs to be done for cpurta!");
return false;
} else if (cpurta.getIA() == null) {
log.debug("IA Setting needs to be done for cpurta!");
return false;
} else if (cpurta.getPUl().size() == 0) {
log.debug("PUl Setting needs to be done for cpurta!");
return false;
} else if (cpurta.getCT() == null) {
log.debug("CT Setting needs to be done for cpurta!");
return false;
}
return true;
}
/**
* Reaction: The time between one of the chain's first task instances to the earliest one of the chain's last task instances
* which are propagated from the initial one. (which we can also call the best-case task-chain age latency)
* the best-case E2E Chain Reaction(Direct or Implicit) = Sum of all entities' BCRT
* @param ec the observed event chain
* @param paradigm communication paradigm (DIRECT, IMPLICIT)
* @param cpurta the instance of CPURta class
* @return
* the best-case E2E Chain Reaction(Direct or Implicit)
*/
public Time getTCReactionBC(final EventChain ec, final ComParadigm paradigm, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eRctImplicit = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
for (int i = 0; i < taskChain.size(); i++) {
final Task task = taskChain.get(i);
final ProcessingUnit pu = getPU(task, cpurta);
final List<Task> taskList = getSortedTaskList(task, pu, cpurta);
Time bcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isMappedToCPU(task, cpurta)) {
if (paradigm.equals(ComParadigm.DIRECT)) {
bcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.BCET, pu);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
bcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.BCET, pu, cpurta);
} else {
log.error("'COM_PARADIGM == null' does not work.");
return null;
}
} else {
bcrt = cpurta.getTRT().get(task);
}
/* The task is not schedulable */
final BigInteger biPeriod = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(task));
if (AmaltheaServices.convertToPicoSeconds(bcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
e2eRctImplicit = e2eRctImplicit.add(bcrt);
}
return e2eRctImplicit;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* The worst case task chain reaction latency for Direct or Implicit Communication
* @param ec the observed event chain
* @param paradigm communication paradigm (DIRECT, IMPLICIT)
* @param cpurta the instance of CPURta class
* @return
* the worst-case E2E Chain Reaction(Direct or Implicit)
*/
public Time getTCReactionWC(final EventChain ec, final ComParadigm paradigm, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eRctWC = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
for (int i = 0; i < taskChain.size() - 1; i++) {
final Task task = taskChain.get(i);
final Time period = CommonUtils.getStimInTime(task);
e2eRctWC = e2eRctWC.add(period.multiply(2));
}
final Task task = taskChain.get(taskChain.size() - 1);
Time wcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isMappedToCPU(task, cpurta)) {
final ProcessingUnit pu = getPU(task, cpurta);
final List<Task> taskList = getSortedTaskList(task, pu, cpurta);
if (paradigm.equals(ComParadigm.DIRECT)) {
wcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.WCET, pu);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
wcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.WCET, pu, cpurta);
} else {
log.error("'COM_PARADIGM == null' does not work.");
return null;
}
} else {
wcrt = cpurta.getTRT().get(task);
}
/* The task is not schedulable */
final BigInteger biPeriod = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(task));
if (AmaltheaServices.convertToPicoSeconds(wcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
e2eRctWC = e2eRctWC.add(wcrt);
return e2eRctWC;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* Reaction: The time between one of the chain's first task instances to the earliest one of the chain's last task instances
* which are propagated from the initial one. (which we can also call the best-case task-chain age latency)
* the best-case E2E Chain Reaction(LET) = Sum of all entities' periods
* @param ec the observed event chain
* @param cpurta the instance of CPURta class
* @return
* the best-case E2E Chain Reaction(LET)
*/
public Time getLetReactionBC(final EventChain ec, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eRctLET = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
for (int i = 0; i < taskChain.size(); i++) {
final Task task = taskChain.get(i);
e2eRctLET = e2eRctLET.add(CommonUtils.getStimInTime(task));
}
return e2eRctLET;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* The worst case task chain reaction latency for LET Communication
* @param ec the observed event chain
* @param cpurta the instance of CPURta class
* @return
* the worst-case E2E Chain Reaction(LET)
*/
public Time getLetReactionWC(final EventChain ec, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eRctWC = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
final Task task0 = taskChain.get(0);
final Time period0 = CommonUtils.getStimInTime(task0);
e2eRctWC = e2eRctWC.add(period0);
for (int i = 1; i < taskChain.size(); i++) {
final Task task = taskChain.get(i);
final Time period = CommonUtils.getStimInTime(task);
e2eRctWC = e2eRctWC.add(period.multiply(2));
}
return e2eRctWC;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* A task chain age latency equals the chain's last (response) task age latency
* worst-case: period - bcrt + wcrt
* best-case: period - wcrt + bcrt
* @param ec the observed event chain
* @param executionCase WCET / BCET
* @param paradigm communication paradigm (DIRECT, IMPLICIT)
* @param cpurta the instance of CPURta class
* @return
* the worst-case E2E Task-Chain Age
*/
public Time getTaskChainAge(final EventChain ec, final TimeType executionCase, final ComParadigm paradigm, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eTCAgeWC = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
final Task task = taskChain.get(taskChain.size()-1);
if (isMappedToCPU(task, cpurta)) {
final Time period = CommonUtils.getStimInTime(task);
final ProcessingUnit pu = getPU(task, cpurta);
final List<Task> taskList = getSortedTaskList(task, pu, cpurta);
Time bcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
Time wcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (paradigm.equals(ComParadigm.DIRECT)) {
bcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.BCET, pu);
wcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.WCET, pu);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
bcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.BCET, pu, cpurta);
wcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.WCET, pu, cpurta);
} else {
log.error("'COM_PARADIGM == null' does not work.");
return null;
}
/* The task is not schedulable */
final BigInteger biPeriod = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(task));
if (AmaltheaServices.convertToPicoSeconds(bcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
} else if (AmaltheaServices.convertToPicoSeconds(wcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
if (executionCase.equals(TimeType.WCET)) {
e2eTCAgeWC = period.subtract(bcrt).add(wcrt);
} else if (executionCase.equals(TimeType.BCET)) {
e2eTCAgeWC = period.subtract(wcrt).add(bcrt);
} else {
log.error("Only WCET or BCET is allowed!");
return null;
}
} else {
// TODO: if the observed task is mapped to GPU, then how should we calculate wcrt, bcrt?
log.debug("GPU Task, how should we calculate wcrt, bcrt?");
}
return e2eTCAgeWC;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* The method is to be used for calculating 'reaction update'.
* @param ec the observed event chain
* @param executionCase WCET / BCET
* @param paradigm communication paradigm (DIRECT, IMPLICIT)
* @param cpurta the instance of CPURta class
* @return
* the reaction latency value of the observed event chain
*/
public Time getEarlyReaction(final EventChain ec, final TimeType executionCase, final ComParadigm paradigm, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
Time e2eEarlyRct = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isTheRTAClassReady(cpurta)) {
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
final Task task0 = taskChain.get(0);
Time rt0 = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isMappedToCPU(task0, cpurta)) {
final ProcessingUnit pu = getPU(task0, cpurta);
final List<Task> taskList = getSortedTaskList(task0, pu, cpurta);
if (paradigm.equals(ComParadigm.DIRECT)) {
rt0 = cpurta.preciseTestCPURT(task0, taskList, executionCase, pu);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
rt0 = cpurta.implicitPreciseTest(task0, taskList, executionCase, pu, cpurta);
} else {
log.error("'COM_PARADIGM == null' does not work.");
return null;
}
} else {
rt0 = cpurta.getTRT().get(task0);
}
/* The task is not schedulable */
final BigInteger biPeriod0 = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(task0));
if (AmaltheaServices.convertToPicoSeconds(rt0).compareTo(biPeriod0) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
e2eEarlyRct = e2eEarlyRct.add(rt0);
Time epsilon = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
for (int i = 0; i < taskChain.size() - 1; i++) {
final Time nextPeriod = CommonUtils.getStimInTime(taskChain.get(i + 1));
/* SUM (Sigma Starts) */
final Time period = CommonUtils.getStimInTime(taskChain.get(i));
final Task currentTask = taskChain.get(i);
Time rtA = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isMappedToCPU(currentTask, cpurta)) {
final ProcessingUnit puA = getPU(currentTask, cpurta);
final List<Task> taskListA = getSortedTaskList(currentTask, puA, cpurta);
/* NOTE: Sometimes rtA, rtB are BigInteger.valueOf(Long.MAX_VALUE) if it is executed with the implicit communication paradigm */
/* In that case, the task is not schedulable, so the method should return 0 ps, otherwise the result is not correct and
* would likely be negative (subtract the max BigIntegerValue would be obviously negative in most cases) */
if (paradigm.equals(ComParadigm.DIRECT)) {
rtA = cpurta.preciseTestCPURT(currentTask, taskListA, executionCase, puA);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
rtA = cpurta.implicitPreciseTest(currentTask, taskListA, executionCase, puA, cpurta);
}
} else {
rtA = cpurta.getTRT().get(currentTask);
}
/* The task is not schedulable */
final BigInteger biPeriod = AmaltheaServices.convertToPicoSeconds(period);
if (AmaltheaServices.convertToPicoSeconds(rtA).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
final Time currentEpsilon = (((period.multiply(2)).subtract(rtA)).subtract(nextPeriod)).subtract(epsilon);
epsilon = currentEpsilon;
final Task nextTask = taskChain.get(i + 1);
Time rtB = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (isMappedToCPU(nextTask, cpurta)) {
final ProcessingUnit puB = getPU(nextTask, cpurta);
final List<Task> taskListB = getSortedTaskList(nextTask, puB, cpurta);
if (paradigm.equals(ComParadigm.DIRECT)) {
rtB = cpurta.preciseTestCPURT(nextTask, taskListB, executionCase, puB);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
rtB = cpurta.implicitPreciseTest(nextTask, taskListB, executionCase, puB, cpurta);
}
} else {
rtB = cpurta.getTRT().get(nextTask);
}
/* The task is not schedulable */
final BigInteger biPeriodB = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(nextTask));
if (AmaltheaServices.convertToPicoSeconds(rtB).compareTo(biPeriodB) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
if (nextPeriod.compareTo(currentEpsilon.add(rtB)) < 0) {
e2eEarlyRct = e2eEarlyRct.add(nextPeriod.multiply(2));
} else {
e2eEarlyRct = e2eEarlyRct.add(nextPeriod.add(currentEpsilon.add(rtB)));
}
if (e2eEarlyRct.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) < 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
}
return e2eEarlyRct;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* the longest time some data version persists in memory.
* worst-case: min (worst-case age latencies of the tasks that contain the observed label)
* best-case: min (best-case age latencies of the tasks that contain the observed label)
* @param label the observed label (data)
* @param ec the observed event-chain
* @param executionCase WCET / BCET
* @param paradigm communication paradigm (DIRECT, IMPLICIT)
* @param cpurta the instance of CPURta class
* @return
* the data age latency (wc or bc) of the given label
* If any of tasks in the chain does not contain the observed label, the method shall return null.
*/
public Time getDataAge(final Label label, final EventChain ec, final TimeType executionCase, final ComParadigm paradigm, final CPURta cpurta) {
final Logger log = Logger.getLogger(E2ELatency.class);
if (isTheRTAClassReady(cpurta)) {
final List<Time> dataAgeList = new ArrayList<Time>();
final List<Task> taskChain = getECTaskList(ec);
if (taskChain.size() == 0) {
log.error("This task chain is empty.");
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
for (int i = 0; i < taskChain.size(); i++) {
if (isMappedToCPU(taskChain.get(i), cpurta)) {
final Task task = taskChain.get(i);
final Set<Label> labelSet = SoftwareUtil.getAccessedLabelSet(task, null);
if(labelSet.contains(label)) {
Time dataAge = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
final ProcessingUnit pu = getPU(task, cpurta);
final List<Task> taskList = getSortedTaskList(task, pu, cpurta);
final Time period = CommonUtils.getStimInTime(task);
Time bcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
Time wcrt = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
if (paradigm.equals(ComParadigm.DIRECT)) {
bcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.BCET, pu);
wcrt = cpurta.preciseTestCPURT(task, taskList, TimeType.WCET, pu);
} else if (paradigm.equals(ComParadigm.IMPLICIT)) {
bcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.BCET, pu, cpurta);
wcrt = cpurta.implicitPreciseTest(task, taskList, TimeType.WCET, pu, cpurta);
} else {
log.error("'COM_PARADIGM == null' does not work.");
return null;
}
/* The task is not schedulable */
final BigInteger biPeriod = AmaltheaServices.convertToPicoSeconds(CommonUtils.getStimInTime(task));
if (AmaltheaServices.convertToPicoSeconds(bcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
} else if (AmaltheaServices.convertToPicoSeconds(wcrt).compareTo(biPeriod) > 0) {
return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS);
}
if (executionCase.equals(TimeType.WCET)) {
dataAge = period.subtract(bcrt).add(wcrt);
} else if (executionCase.equals(TimeType.BCET)) {
dataAge = period.subtract(wcrt).add(bcrt);
} else {
log.error("Only WCET or BCET is allowed!");
}
dataAgeList.add(dataAge);
}
}
}
if (dataAgeList.size() != 0) {
Collections.sort(dataAgeList, new TimeComp());
return dataAgeList.get(0);
}
return null;
}
log.error("cpurta instance is not ready!");
return null;
}
/**
* Get an Event-Chain Entity List (Task-based)
* @param ec the observed event chain
* @return
* the corresponding EC task list
*/
public List<Task> getECTaskList(final EventChain ec) {
final List<Task> chain = new ArrayList<Task>();
for (int i = 0; i < ec.getSegments().size(); i++) {
final EventChainItem eci = ec.getSegments().get(i);
if (eci instanceof EventChainContainer) {
final EventChainContainer ecc = (EventChainContainer) eci;
final Event stiEvent = ecc.getEventChain().getStimulus();
if (stiEvent instanceof ProcessEvent) {
final Task stiTask = (Task)((ProcessEvent) stiEvent).getEntity();
chain.add(stiTask);
}
if (i == ec.getSegments().size() - 1) {
final Event resEvent = ecc.getEventChain().getResponse();
if (resEvent instanceof ProcessEvent) {
final Task resTask = (Task)((ProcessEvent) resEvent).getEntity();
chain.add(resTask);
}
break;
}
}
}
return chain;
}
/**
* get the processing unit that the observed task is mapped to
* @param task the observed task
* @param cpurta the instance of CPURta class
* @return
* pu
*/
private ProcessingUnit getPU(final Task task, final CPURta cpurta) {
final int tindex = cpurta.getModel().getSwModel().getTasks().indexOf(task);
final int puindex = cpurta.getIA()[tindex];
final ProcessingUnit pu = cpurta.getPUl().get(puindex);
return pu;
}
/**
* get the sorted task listed based on the given integer array mapping
* @param task the observed task
* @param pu ProcessingUnit that would compute the given method
* @param cpurta the instance of CPURta class
* @return
* sortedTaskList
*/
private List<Task> getSortedTaskList(final Task task, final ProcessingUnit pu, final CPURta cpurta) {
final int puIndex = cpurta.getPUl().indexOf(pu);
/* 2. get all tasks mapped to this CPU */
final List<Task> puTaskList = new ArrayList<Task>();
for (int i = 0; i < cpurta.getIA().length; i++) {
if (cpurta.getIA()[i] == puIndex) {
puTaskList.add(cpurta.getModel().getSwModel().getTasks().get(i));
}
}
final List<Task> sortedTaskList = taskSorting(puTaskList);
return sortedTaskList;
}
/**
* Sort out the given list of tasks (in order of shorter period first - Rate Monotonic Scheduling)
* @param taskList list of tasks that is mapped to the same core
* @return
* the sorted list of tasks
*/
private List<Task> taskSorting(final List<Task> taskList) {
/* Getting stimuliList out of the given taskList (because it is RMS) */
final List<Time> stimuliList = new ArrayList<>();
for (final Task t : taskList) {
stimuliList.add(CommonUtils.getStimInTime(t));
}
/* Sorting (Shortest Period(Time) first) */
Collections.sort(stimuliList, new TimeComp());
/* Sort tasks to the newTaskList in order of Period length (shortest first
* longest last)-(according to the stimuliList) */
final List<Task> newTaskList = new ArrayList<>();
for (int i = 0; i < stimuliList.size(); i++) {
for (final Task t : taskList) {
if ((!newTaskList.contains(t)) && (stimuliList.get(i).compareTo(CommonUtils.getStimInTime(t)) == 0)) {
newTaskList.add(t);
}
}
}
return newTaskList;
}
/**
* To check whether or not the observed task is mapped to CPU (according to the integer array)
* @param task the observed task
* @param cpurta the instance of CPURta class that contains model & mapping IA info
* @return
* boolean value that says whether or not it is mapped to CPU
*/
private static boolean isMappedToCPU (final Task task, final CPURta cpurta) {
/* The observed task is a GPU task */
if (cpurta.getGpuTaskList().contains(task)) {
final int index = cpurta.getModel().getSwModel().getTasks().indexOf(task);
final int cpuThreshold = CommonUtils.getNumberofCPUs(cpurta.getModel()) - 1;
final int[] ia = cpurta.getIA();
/* when the observed GPU task is mapped to GPU */
if (ia[index] > cpuThreshold) {
return false;
}
}
/* when the observed task(CPU or GPU) is mapped to CPU */
return true;
}
}
/**
* @Date: August 21-2019
* @version 1.0
* This inner class is used for sorting a Time type list.
* If the Time of a is smaller than that of b, it returns -1.
* If the Time of a is bigger than that of b, it returns 1.
*/
class TimeComp implements Comparator<Time> {
@Override
public int compare(final Time a, final Time b) {
if (a.compareTo(b) < 0) {
return -1;
}
return 1;
}
}
/**
* @Date: August 21-2019
* @version 1.0
* This inner class is used for the method "letCom" to help compare between different values of propagation, age, reaction
* in basicPaths (which is bigger)
* If the BigDecimal of a is smaller than that of b, it returns -1.
* If the BigDecimal of a is bigger than that of b, it returns 1.
*/
class BigDecimalComp implements Comparator<BigDecimal> {
@Override
public int compare(final BigDecimal a, final BigDecimal b) {
if (a.compareTo(b) < 0) {
return -1;
}
return 1;
}
}