/******************************************************************************* | |
* 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; | |
} | |
} |