| /******************************************************************************* |
| * 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.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| import org.apache.log4j.Level; |
| import org.apache.log4j.Logger; |
| import org.eclipse.app4mc.amalthea.model.Amalthea; |
| import org.eclipse.app4mc.amalthea.model.CallSequenceItem; |
| import org.eclipse.app4mc.amalthea.model.ClearEvent; |
| import org.eclipse.app4mc.amalthea.model.InterProcessStimulus; |
| import org.eclipse.app4mc.amalthea.model.InterProcessTrigger; |
| import org.eclipse.app4mc.amalthea.model.Label; |
| import org.eclipse.app4mc.amalthea.model.LabelAccess; |
| import org.eclipse.app4mc.amalthea.model.LabelAccessEnum; |
| import org.eclipse.app4mc.amalthea.model.Preemption; |
| import org.eclipse.app4mc.amalthea.model.ProcessingUnit; |
| import org.eclipse.app4mc.amalthea.model.PuType; |
| import org.eclipse.app4mc.amalthea.model.Runnable; |
| import org.eclipse.app4mc.amalthea.model.SetEvent; |
| import org.eclipse.app4mc.amalthea.model.Task; |
| import org.eclipse.app4mc.amalthea.model.TaskRunnableCall; |
| import org.eclipse.app4mc.amalthea.model.Time; |
| import org.eclipse.app4mc.amalthea.model.TimeUnit; |
| import org.eclipse.app4mc.amalthea.model.WaitEvent; |
| 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.emf.common.util.EList; |
| |
| /** |
| * Date: August 21-2019 |
| * @author Junhyung Ki |
| * @version 1.0 |
| * This class is to analyze response time of CPU(e.g., ARM, Denver cores) Tasks in CPU-GPU Heterogeneous Systems |
| * The entire class is designed for Generic Algorithm Mapping to find the most optimized task mapping solution. |
| * Therefore, setting the integer array variable, 'tpuMapping' (which is considered as a mapping solution) along with |
| * others ( Amalthea Model, 'model' setting, Task Response Time HashMap, 'trt' setting (for GPU Tasks), Processing Unit List, 'pul' setting |
| * should be the first step before executing any response time method. (Which is done by the constructor) |
| */ |
| public class CPURta { |
| public final File inputFile = new File("model-input/WATERS19_release/ChallengeModel_release.amxmi"); |
| |
| /** |
| * Get Default IA Map |
| * @return |
| * this.defaultIAMapping |
| */ |
| public int[] getDefaultIAMapping() { |
| return SharedConsts.defaultIAMapping; |
| } |
| |
| private Amalthea model = null; |
| |
| /** |
| * Constructor only for testing the class |
| */ |
| public CPURta() { |
| final Logger log = Logger.getLogger(CPURta.class); |
| final Amalthea pModel = AmaltheaLoader.loadFromFile(this.inputFile); |
| if (pModel == null) { |
| log.error("Model is empty. Please check the model path."); |
| return; |
| } else { |
| this.setModel(AmaltheaLoader.loadFromFile(this.inputFile)); |
| } |
| this.setTRT(this.getDefaultTRT(this.getModel())); |
| this.setIA(this.getDefaultIAMapping()); |
| this.setPUl(CommonUtils.getPUs(this.getModel())); |
| } |
| |
| /** |
| * CPURta Constructor |
| * @param model the observed Amalthea Model |
| * @param trt the observed HashMap Task with Response Time (null works => the default testing trt will be assigned) |
| * @param ia the observed IntegerArray Mapping Model |
| * @param pul the observed List of ProcessingUnits |
| */ |
| public CPURta(final Amalthea model, final HashMap<Task, Time> trt, final int[] ia, final List<ProcessingUnit> pul) { |
| this.setModel(model); |
| if (trt == null) { |
| this.setTRT(this.getDefaultTRT(this.getModel())); |
| } else { |
| this.setTRT(trt); |
| } |
| this.setIA(ia); |
| this.setPUl(pul); |
| } |
| |
| /** |
| * Since this method is used by RTARuntimeUtil, the visibility should be 'public' |
| * @return |
| * The Amalthea model object of the current CPURta class |
| */ |
| public Amalthea getModel() { |
| return this.model; |
| } |
| |
| /** |
| * Set the Amalthea model object of the current CPURta class as the given Amalthea model parameter. |
| * @param pAmalthea the parameter Amalthea model which would reinitialize the Amalthea model |
| */ |
| public void setModel(final Amalthea pAmalthea) { |
| this.model = pAmalthea; |
| this.setGTCL(this.model); |
| } |
| |
| private HashMap<Task, Time> trt = null; |
| |
| /** |
| * Since this method is used by GAMapping, the visibility should be 'public' |
| * @return |
| * trt(task with response time) HashMap variable |
| */ |
| public HashMap<Task, Time> getTRT() { |
| return this.trt; |
| } |
| |
| /** |
| * Set the trt(task with response time) HashMap variable as the given trtp parameter variable. |
| * Which would contains GPU tasks' response times from the beginning |
| * @param trtp the HashMap variable parameter which would reinitialize the trt variable of the current CPURta class. |
| */ |
| public void setTRT(final HashMap<Task, Time> trtp) { |
| this.trt = trtp; |
| } |
| |
| /** |
| * Get the default trt(task with response time) value in case of running CPURta class itself. |
| * @param model the current class's Amalthea model which is used to get the trt value out of it |
| * @return |
| * the trt value which is derived out of the given parameter Amalthea model |
| */ |
| public HashMap<Task, Time> getDefaultTRT(final Amalthea model) { |
| final HashMap<Task, Time> trt = new HashMap<Task, Time>(); |
| final EList<Task> allTaskList = model.getSwModel().getTasks(); |
| final long val = 2000000000; |
| for (final Task t : allTaskList) { |
| if (this.gpuTaskList.contains(t)) { |
| trt.put(t, FactoryUtil.createTime(BigInteger.valueOf(val), TimeUnit.PS)); |
| } else { |
| trt.put(t, FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)); |
| } |
| } |
| return trt; |
| } |
| |
| private int[] tpuMapping = null; |
| |
| /** |
| * Since this method is used by RTARuntimeUtil, the visibility should be 'public' |
| * @return |
| * The tpuMapping integer array |
| */ |
| public int[] getIA() { |
| return this.tpuMapping; |
| } |
| |
| /** |
| * Set the tpuMapping integer array (which would be used to modify the current task mapping to different Processing Units) |
| * as the given tpumap parameter variable. |
| * (The integer array would be used to modify the current task mapping to different Processing Units) |
| * @param tpumap the parameter integer array which would reinitialize the tpuMapping array of the current CPURta class. |
| */ |
| public void setIA(final int[] tpumap) { |
| final Logger log = Logger.getLogger(CPURta.class); |
| if (tpumap == null) { |
| this.tpuMapping = null; |
| } else if (tpumap.length == this.model.getSwModel().getTasks().size()) { |
| this.tpuMapping = tpumap; |
| } else { |
| log.error("integer array size MUST match the number of tasks"); |
| } |
| } |
| |
| private List<ProcessingUnit> pul = new ArrayList<>(); |
| |
| /** |
| * Get a list of ProcessingUnits |
| * @return |
| * this.pul |
| */ |
| public List<ProcessingUnit> getPUl() { |
| return this.pul; |
| } |
| |
| /** |
| * Set the pul, the list of Processing Units variable (which would be used to map tasks along with tpuMapping array) |
| * as the given pul parameter variable. |
| * @param pul the parameter pul list which would reinitialize the pul list variable of the current CPURta class |
| */ |
| public void setPUl(final List<ProcessingUnit> pul) { |
| this.pul = pul; |
| } |
| |
| private Contention ct = null; |
| |
| /** |
| * Get the contention instance |
| * |
| * @return |
| * this.ct |
| */ |
| public Contention getCT() { |
| return this.ct; |
| } |
| |
| /** |
| * Set the ct (Contention) variable which would be used to calculate memory contention of the given task that will be added up to the response time result |
| * as the newly generated contention instance with the given integer array |
| * and Amalthea model parameters. |
| * @param ia Integer Array which is referred to map tasks of the given model |
| * @param model Amalthea model |
| */ |
| public void setContention(final int[] ia, final Amalthea model) { |
| this.ct = new Contention(ia, model); |
| } |
| |
| private List<Task> gpuTaskList = new ArrayList<Task>(); |
| |
| /** |
| * Since this method is used by RTARuntimeUtil, the visibility should be 'protected' |
| * @return |
| * gpuTaskList which contains tasks (which are originally designed for GPU) of the Amalthea model |
| */ |
| protected List<Task> getGpuTaskList() { |
| return this.gpuTaskList; |
| } |
| |
| private final List<Task> triggeringTaskList = new ArrayList<Task>(); |
| /** |
| * Since this method is used by RTARuntimeUtil, the visibility should be 'protected' |
| * @return |
| * triggeringTaskList which contains tasks (which contain InterProcessTrigger) of the Amalthea model |
| */ |
| protected List<Task> getTriggeringTaskList() { |
| return this.triggeringTaskList; |
| } |
| |
| /* this runnable is used to calculate execution time in RTARuntimeUtil class */ |
| protected Runnable offloadingAsyncRunnable = null; |
| |
| private final HashMap<Task, List<List<Label>>> gpuToCpuLabels = new HashMap<Task, List<List<Label>>>(); |
| |
| /** |
| * Since this method is used by RTARuntimeUtil, the visibility should be 'protected' |
| * @return |
| * gpuToCpuLabels HashMap which contains required labels (of the corresponding task) |
| * that need to be taken into account when GPU tasks are mapped to CPU |
| */ |
| protected HashMap<Task, List<List<Label>>> getGTCL() { |
| return this.gpuToCpuLabels; |
| } |
| |
| /** |
| * Not only set gpuToCpuLabels HashMap, this also set gpuTaskList (only contains GPU tasks), |
| * triggeringTaskList (only contains tasks with InterProcessTrigger) |
| * and offloadingAsyncRunnable (the Runnable that is taken into account for triggering tasks when the mode is asynchronous) |
| * @param model the parameter Amalthea model which is used to derived required labels of the corresponding GPU task |
| */ |
| private void setGTCL(final Amalthea model) { |
| if (model != null) { |
| final EList<Task> allTaskList = model.getSwModel().getTasks(); |
| this.gpuTaskList = allTaskList.stream().filter(s -> s.getStimuli().get(0) instanceof InterProcessStimulus).collect(Collectors.toList()); |
| /* find the triggering tasks */ |
| for (final Task t : allTaskList) { |
| final List<CallSequenceItem> triggerList = SoftwareUtil.collectCalls(t, null, |
| (call -> call instanceof InterProcessTrigger)); |
| if (triggerList.size() != 0) { |
| this.triggeringTaskList.add(t); |
| if (RTARuntimeUtil.doesTaskHaveAsyncRunnable(t, this)) { |
| final List<CallSequenceItem> cList = SoftwareUtil.collectCalls(t, null, (call -> call instanceof TaskRunnableCall || |
| call instanceof InterProcessTrigger || call instanceof ClearEvent || call instanceof SetEvent || call instanceof WaitEvent)); |
| final int waitIndex = cList.indexOf(cList.stream().filter(s -> s instanceof WaitEvent).iterator().next()); |
| final int asyncOffloadingIndex = waitIndex + 1; |
| if (cList.get(asyncOffloadingIndex) instanceof TaskRunnableCall) { |
| this.offloadingAsyncRunnable = ((TaskRunnableCall) cList.get(asyncOffloadingIndex)).getRunnable(); |
| } |
| } |
| } |
| } |
| for (final Task t : this.gpuTaskList) { |
| final InterProcessStimulus ips = (InterProcessStimulus) (t.getStimuli().get(0)); |
| Task triggeringTask = null; |
| for (final Task tt : this.triggeringTaskList) { |
| final InterProcessTrigger ipt = (InterProcessTrigger) SoftwareUtil.collectCalls(tt, null, |
| (call -> call instanceof InterProcessTrigger)).stream().iterator().next(); |
| if (ips.equals(ipt.getStimulus())) { |
| triggeringTask = tt; |
| break; |
| } |
| } |
| final List<Label> readLabelList = new ArrayList<Label>(); |
| final List<Label> writeLabelList = new ArrayList<Label>(); |
| final List<CallSequenceItem> callList = SoftwareUtil.collectCalls(triggeringTask, null, (call -> call instanceof TaskRunnableCall || |
| call instanceof InterProcessTrigger || call instanceof ClearEvent || call instanceof SetEvent || call instanceof WaitEvent)); |
| final InterProcessTrigger ipt = (InterProcessTrigger) callList.stream().filter(s -> s instanceof InterProcessTrigger).iterator().next(); |
| final int indexforTrigger = callList.indexOf(ipt); |
| for (int i = 0; i < callList.size(); i++) { |
| Runnable thisRunnable = null; |
| /* Pre-processing Runnable */ |
| if ((i < indexforTrigger) && (callList.get(i) instanceof TaskRunnableCall)) { |
| thisRunnable = (Runnable) ((TaskRunnableCall) callList.get(i)).getRunnable(); |
| final List<LabelAccess> thisLAList = SoftwareUtil.getLabelAccessList(thisRunnable, null); |
| for (final LabelAccess la : thisLAList) { |
| if (la.getAccess().equals(LabelAccessEnum.READ)) { |
| readLabelList.add(la.getData()); |
| } |
| } |
| } |
| /* Post-processing Runnable */ |
| else if ((i > indexforTrigger) && (callList.get(i) instanceof TaskRunnableCall)) { |
| thisRunnable = ((TaskRunnableCall) callList.get(i)).getRunnable(); |
| final List<LabelAccess> thisLAList = SoftwareUtil.getLabelAccessList(thisRunnable, null); |
| for (final LabelAccess la : thisLAList) { |
| if (la.getAccess().equals(LabelAccessEnum.WRITE)) { |
| writeLabelList.add(la.getData()); |
| } |
| } |
| } |
| } |
| final List<List<Label>> listOfLabelList = new ArrayList<List<Label>>(); |
| listOfLabelList.add(readLabelList); |
| listOfLabelList.add(writeLabelList); |
| this.gpuToCpuLabels.put(t, listOfLabelList); |
| } |
| } else { |
| this.gpuTaskList.clear(); |
| this.triggeringTaskList.clear(); |
| this.offloadingAsyncRunnable = null; |
| this.gpuToCpuLabels.clear(); |
| } |
| } |
| |
| /* To calculate pure memory access latency cost (without contention & pure computation(Ticks)) */ |
| protected Time cumuAcTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| |
| /** |
| * @return |
| * cumuAcTime, the total time of latency (Read & Write memory access) from CPUs |
| */ |
| public Time getCumulatedMemAccCosts() { |
| return this.cumuAcTime; |
| } |
| |
| /** |
| * Initializing cumuAcTime to 0 ps |
| */ |
| public void initCumulatedMemAccCosts() { |
| this.cumuAcTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| } |
| |
| /* To calculate pure latency cost (without memory access latency & pure computation(Ticks)) */ |
| protected Time cumuConTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| |
| /** |
| * @return |
| * cumulatedCon, the total time of latency (Contention of the task) |
| */ |
| public Time getCumulatedContention() { |
| return this.cumuConTime; |
| } |
| |
| /** |
| * Initializing cumulatedCon to 0 ps |
| */ |
| public void initCumulatedContention() { |
| this.cumuConTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| } |
| |
| public static void main(String[] args) { |
| org.apache.log4j.BasicConfigurator.configure(); |
| Logger.getRootLogger().setLevel(Level.ERROR); |
| final CPURta cpurta = new CPURta(); |
| cpurta.run(); |
| } |
| |
| /** |
| * Executable method |
| */ |
| public void run() { |
| final Logger log = Logger.getLogger(CPURta.class); |
| if (this.model == null) { |
| log.error("No model loaded!"); |
| return; |
| } |
| log.debug("\n####################### The Test ########################\n"); |
| log.debug("RT Time Sum: " + getCPUResponseTimeSum(SharedConsts.timeType)); |
| } |
| |
| /** |
| * Calculate the total sum of response times of the tasks of the given Amalthea model with the mapping model (tpuMapping) |
| * @param executionCase BCET, ACET, WCET |
| * @return |
| * total sum of all tasks' response times of the given mapped model (tpuMapping) |
| */ |
| public Time getCPUResponseTimeSum(final TimeType executionCase) { |
| final Logger log = Logger.getLogger(CPURta.class); |
| if (this.model == null) { |
| log.error("No Model Loaded!"); |
| return null; |
| } else if (this.trt == null) { |
| log.error("No HashMap Loaded!"); |
| return null; |
| } else if (this.tpuMapping == null) { |
| log.error("No IntegerArray Loaded!"); |
| return null; |
| } else if (this.pul == null) { |
| log.error("No PUList Loaded!"); |
| return null; |
| } |
| this.setContention(this.getIA(), this.getModel()); |
| Time time = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| for (int i = 0; i < this.tpuMapping.length; i++) { |
| final Time rt = getTaskCPURT(this.model.getSwModel().getTasks().get(i), executionCase); |
| if (rt.getValue().equals(BigInteger.valueOf(Long.MAX_VALUE)) && !SharedConsts.ignoreInfeasibility) { |
| return rt; |
| } |
| time = time.add(rt); |
| if (!rt.getValue().equals(BigInteger.ZERO)) { |
| /* only put CPU tasks */ |
| this.trt.put(this.model.getSwModel().getTasks().get(i), rt); |
| } |
| } |
| return time; |
| } |
| |
| /** |
| * Calculate response time of the given task of the given Amalthea model with the mapping model (tpuMapping) |
| * @param task the observed task |
| * @param executionCase BCET, ACET, WCET |
| * @return |
| * response time of the observed task |
| */ |
| protected Time getTaskCPURT(final Task task, final TimeType executionCase) { |
| /* 1. validate thisTask is mapped to CPU */ |
| final int tindex = this.model.getSwModel().getTasks().indexOf(task); |
| final int puindex = this.tpuMapping[tindex]; |
| final ProcessingUnit pu = this.pul.get(puindex); |
| if (!pu.getDefinition().getPuType().equals(PuType.CPU)) { |
| Logger.getLogger(CPURta.class).debug(task.getName() + " is not mapped to a CPU"); |
| return FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| } |
| /* 2. get all tasks mapped to this CPU */ |
| final List<Task> puTaskList = new ArrayList<Task>(); |
| for (int i = 0; i < this.tpuMapping.length; i++) { |
| if (this.tpuMapping[i] == puindex) { |
| puTaskList.add(this.model.getSwModel().getTasks().get(i)); |
| } |
| } |
| final List<Task> sortedTaskList = taskSorting(puTaskList); |
| return preciseTestCPURT(task, sortedTaskList, executionCase, pu); |
| } |
| |
| /** |
| * 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 TimeCompIA()); |
| /* 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; |
| } |
| |
| /** |
| * Visibility - public (This method is for the UI version code (ui package > RTApp.java)) |
| * Calculate response time of the observed task according to the periodic tasks response time analysis algorithm. |
| * @param task the observed task |
| * @param taskList list of tasks that is mapped to the same core |
| * @param executionCase BCET, ACET, WCET |
| * @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) |
| * @return |
| * response time of the observed task |
| */ |
| public Time preciseTestCPURT(final Task task, final List<Task> taskList, final TimeType executionCase, final ProcessingUnit pu) { |
| final Logger log = Logger.getLogger(CPURta.class); |
| Time thisRT = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| Time period = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| if (taskList.size() == 0) { |
| log.debug("!!! This taskList is empty so I am returning MAX !!!"); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| /* to check if the given task is in the taskList */ |
| int flag = 0; |
| int index = 0; |
| for (int i = 0; i < taskList.size(); i++) { |
| if (task.equals(taskList.get(i))) { |
| flag = 1; |
| index = i; |
| break; |
| } |
| } |
| if (flag == 0) { |
| log.debug("!!! Nothing in the taskList matches the given Task !!! So I am returning 0s" + " --- thisTask: " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| final RTARuntimeUtil rtaut = new RTARuntimeUtil(); |
| for (int i = 0; i < index + 1; i++) { |
| period = CommonUtils.getStimInTime(taskList.get(i)); |
| if (index == 0) { |
| thisRT = rtaut.getExecutionTimeforCPUTask(taskList.get(i), pu, executionCase, this); |
| if (thisRT.compareTo(period) <= 0) { |
| /* To analyze the pure latency time */ |
| if (thisRT.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) > 0) { |
| this.cumuAcTime = this.cumuAcTime.add(rtaut.getTaskMemoryAccessTime(task, pu, executionCase)); |
| this.cumuConTime = this.cumuConTime.add(this.getCT().contentionForTask(task)); |
| } |
| return thisRT; |
| } |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the execution time of " + thisRT |
| + " for task " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } else if (i == index) { |
| /* In the case of a COOPERATIVE Preemption typed Task */ |
| if (taskList.get(i).getPreemption().equals(Preemption.COOPERATIVE)) { |
| // TODO: Blocking |
| } |
| final Time thisExeTime = rtaut.getExecutionTimeforCPUTask(taskList.get(i), pu, executionCase, this); |
| if (thisExeTime.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) == 0) { |
| return thisExeTime; |
| } else if (thisExeTime.compareTo(period) > 0) { |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the execution time of " + thisRT |
| + " for task " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| Time culmulativeRT = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| /* 1. add all the execution time till the index */ |
| for (int j = 0; j < i + 1; j++) { |
| final Time thisTime = rtaut.getExecutionTimeforCPUTask(taskList.get(j), pu, executionCase, this); |
| culmulativeRT = culmulativeRT.add(thisTime); |
| } |
| if (culmulativeRT.compareTo(period) <= 0) { |
| while (true) { |
| Time excepThisExeTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| for (int k = 0; k < i; k++) { |
| Time localPeriod = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| localPeriod = CommonUtils.getStimInTime(taskList.get(k)); |
| final Time preExeTime = rtaut.getExecutionTimeforCPUTask(taskList.get(k), pu, executionCase, this); |
| final double ri_period = Math.ceil(culmulativeRT.divide(localPeriod)); |
| excepThisExeTime = excepThisExeTime.add(preExeTime.multiply(ri_period)); |
| } |
| Time culmulativeRT_x = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| culmulativeRT_x = thisExeTime.add(excepThisExeTime); |
| if (culmulativeRT_x.compareTo(period) <= 0) { |
| if (culmulativeRT_x.compareTo(culmulativeRT) == 0) { |
| thisRT = culmulativeRT_x; |
| /* To analyze the pure latency time */ |
| if (thisRT.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) > 0) { |
| this.cumuAcTime = this.cumuAcTime.add(rtaut.getTaskMemoryAccessTime(task, pu, executionCase)); |
| this.cumuConTime = this.cumuConTime.add(this.getCT().contentionForTask(task)); |
| } |
| return thisRT; |
| } |
| culmulativeRT = culmulativeRT_x; |
| } else { |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period |
| + " being less than the response time (culmulativeRT_x) of " + culmulativeRT_x + " for task " + task.getName()); |
| if (SharedConsts.ignoreInfeasibility) { |
| return culmulativeRT_x; |
| } |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| } |
| } |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the response time of " + culmulativeRT |
| + " for task " + task.getName()); |
| if (SharedConsts.ignoreInfeasibility) { |
| return culmulativeRT; |
| } |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| } |
| /* To analyze the pure latency time */ |
| if (thisRT.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) > 0) { |
| this.cumuAcTime = this.cumuAcTime.add(rtaut.getTaskMemoryAccessTime(task, pu, executionCase)); |
| this.cumuConTime = this.cumuConTime.add(this.getCT().contentionForTask(task)); |
| } |
| return thisRT; |
| } |
| |
| /** |
| * Calculate response time of the observed task according to the implicit communication paradigm. |
| * @param task the observed task |
| * @param taskList list of tasks that is mapped to the same core |
| * @param executionCase BCET, ACET, WCET |
| * @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) |
| * @param cpurta the instance of CPURta class that contains model & mapping IA info |
| * @return |
| * response time of the observed task (implicit communication paradigm) |
| */ |
| public Time implicitPreciseTest(final Task task, final List<Task> taskList, final TimeType executionCase, |
| final ProcessingUnit pu, final CPURta cpurta) { |
| final Logger log = Logger.getLogger(CPURta.class); |
| Time thisRT = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| Time period = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| if (taskList.size() == 0) { |
| log.debug("!!! This taskList is empty so I am returning MAX !!!"); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| /* to check if the given task is in the taskList */ |
| int flag = 0; |
| int index = 0; |
| for (int i = 0; i < taskList.size(); i++) { |
| if (task.equals(taskList.get(i))) { |
| flag = 1; |
| index = i; |
| break; |
| } |
| } |
| if (flag == 0) { |
| log.debug("!!! Nothing in the taskList matches the given Task !!! So I am returning 0s" + " --- thisTask: " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| final RTARuntimeUtil rtaut = new RTARuntimeUtil(); |
| for (int i = 0; i < index + 1; i++) { |
| period = CommonUtils.getStimInTime(taskList.get(i)); |
| if (index == 0) { |
| thisRT = rtaut.getExecutionTimeforCPUTask(taskList.get(i), pu, executionCase, cpurta); |
| final Time[] ta = rtaut.getLocalCopyTimeArray(taskList.get(i), pu, executionCase, cpurta); |
| for (int j = 0; j < ta.length; j++) { |
| thisRT = thisRT.add(ta[j]); |
| } |
| if (thisRT.compareTo(period) <= 0) { |
| return thisRT; |
| } |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the execution time of " + thisRT |
| + " for task " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } else if (i == index) { |
| /* In the case of a COOPERATIVE Preemption typed Task */ |
| Time thisExeTime = rtaut.getExecutionTimeforCPUTask(taskList.get(i), pu, executionCase, cpurta); |
| final Time[] ta = rtaut.getLocalCopyTimeArray(taskList.get(i), pu, executionCase, cpurta); |
| for (int j = 0; j < ta.length; j++) { |
| thisExeTime = thisExeTime.add(ta[j]); |
| } |
| if (thisExeTime.compareTo(FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS)) == 0) { |
| return thisExeTime; |
| } else if (thisExeTime.compareTo(period) > 0) { |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the execution time of " + thisRT |
| + " for task " + task.getName()); |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| Time culmulativeRT = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| /* 1. add all the execution time till the index */ |
| for (int j = 0; j < i + 1; j++) { |
| Time thisTime = rtaut.getExecutionTimeforCPUTask(taskList.get(j), pu, executionCase, cpurta); |
| final Time[] ta_ = rtaut.getLocalCopyTimeArray(taskList.get(j), pu, executionCase, cpurta); |
| for (int k = 0; k < ta_.length; k++) { |
| thisTime = thisTime.add(ta[k]); |
| } |
| culmulativeRT = culmulativeRT.add(thisTime); |
| } |
| if (culmulativeRT.compareTo(period) <= 0) { |
| while (true) { |
| Time excepThisExeTime = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| for (int j = 0; j < i; j++) { |
| Time localPeriod = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| localPeriod = CommonUtils.getStimInTime(taskList.get(j)); |
| Time preExeTime = rtaut.getExecutionTimeforCPUTask(taskList.get(j), pu, executionCase, cpurta); |
| final Time[] ta_ = rtaut.getLocalCopyTimeArray(taskList.get(j), pu, executionCase, cpurta); |
| for (int k = 0; k < ta_.length; k++) { |
| preExeTime = preExeTime.add(ta_[k]); |
| } |
| final double ri_period = Math.ceil(culmulativeRT.divide(localPeriod)); |
| excepThisExeTime = excepThisExeTime.add(preExeTime.multiply(ri_period)); |
| } |
| Time culmulativeRT_x = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| culmulativeRT_x = thisExeTime.add(excepThisExeTime); |
| if (culmulativeRT_x.compareTo(period) <= 0) { |
| if (culmulativeRT_x.compareTo(culmulativeRT) == 0) { |
| thisRT = culmulativeRT_x; |
| return thisRT; |
| } |
| culmulativeRT = culmulativeRT_x; |
| } else { |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period |
| + " being less than the response time (culmulativeRT_x) of " + culmulativeRT_x + " for task " + task.getName()); |
| if (SharedConsts.ignoreInfeasibility) { |
| return culmulativeRT_x; |
| } |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| } |
| } |
| log.debug("!!! This is non schedulable...!!! Because of the period " + period + " being less than the response time of " + culmulativeRT |
| + " for task " + task.getName()); |
| if (SharedConsts.ignoreInfeasibility) { |
| return culmulativeRT; |
| } |
| return FactoryUtil.createTime(BigInteger.valueOf(Long.MAX_VALUE), TimeUnit.PS); |
| } |
| } |
| return thisRT; |
| } |
| |
| /** |
| * Visibility - public (This method is for the UI version code (ui package > RTApp.java)) |
| * It returns HashMap<Integer, List<Task>> Type reference that contains an Integer(number of Processing Unit index) and the corresponding List of Tasks |
| * This is to visualize which task is mapped to which processing unit. |
| * @return |
| * HashMap<Integer, List<Task>> puListHashMap |
| */ |
| public HashMap<Integer, List<Task>> be_getPUTaskListHashMap(final Amalthea model) { |
| HashMap<Integer, List<Task>> puListHashMap = new HashMap<>(); |
| final EList<Task> allTaskList = model.getSwModel().getTasks(); |
| for(int i = 0; i < this.pul.size(); i++) { |
| final List<Task> puTaskList = new ArrayList<Task>(); |
| for(int j = 0; j < this.tpuMapping.length; j++) { |
| final int puIndex = this.tpuMapping[j]; |
| if (i == puIndex) { |
| puTaskList.add(allTaskList.get(j)); |
| } |
| } |
| puListHashMap.put(i, taskSorting(puTaskList)); |
| } |
| return puListHashMap; |
| } |
| } |
| |
| /** |
| * @Date: August 21-2019 |
| * @author Junhyung Ki |
| * @version 1.0 |
| * This inner class is used for the method "taskSorting" to help compare between two tasks' periods (which is longer) |
| * If the time of arg0 is shorter than that of arg1, it returns -1. |
| * If the time of arg0 is longer than that of arg1, it returns 1. |
| */ |
| class TimeCompIA implements Comparator<Time> { |
| @Override |
| public int compare(final Time arg0, final Time arg1) { |
| if (arg0.compareTo(arg1) < 0) { |
| return -1; |
| } |
| return 1; |
| } |
| } |