/******************************************************************************* | |
* 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.math.BigInteger; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
import org.apache.log4j.Logger; | |
import org.eclipse.app4mc.amalthea.model.AmaltheaServices; | |
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.ProcessingUnit; | |
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.Ticks; | |
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.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 support CPURta class. Response Time Analysis contains low level calculation | |
* such as deriving execution time of a Task or Runnable. Execution time calculation varies depending on the analyzed model. | |
* Therefore, it is necessary to separate from Response Time calculation to increase adaptability. | |
* Only 'getExecutionTimeforCPUTask' method is accessible for CPURta and the rest are sub-methods of it. | |
*/ | |
public class RTARuntimeUtil { | |
/** | |
* Calculate execution time of the given task under one of the four cases with some configurations. | |
* Since this method is used by CPURta, the visibility should be 'public' | |
* 1. triggering task in the synchronous mode | |
* 2. triggering task in the asynchronous mode | |
* 3. GPU task on CPU | |
* 4. task with only Ticks | |
* @param task the observed task | |
* @param pu ProcessingUnit that would compute the given task (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @param cpurta the instance of CPURta class that calls this method | |
* (to access to the cumuAcTime Time variable that accumulate access latency) | |
* @return | |
* execution time of the observed task | |
*/ | |
public Time getExecutionTimeforCPUTask(final Task task, final ProcessingUnit pu, final TimeType executionCase, final CPURta cpurta) { | |
Logger.getLogger(RTARuntimeUtil.class); | |
/* set the default result time variable as 0s */ | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
/* check if the current task is a triggering task. | |
* If so, check whether or not it triggers the target task which is newly mapped to CPU. | |
* In that case, returns 0 ps */ | |
if (doesThisTaskTriggerCPUTask(task, cpurta)) { | |
return result; | |
} | |
/* contention time */ | |
final Time contention = cpurta.getCT().contentionForTask(task); | |
/* The list of runnables of the given task */ | |
final List<Runnable> runnableList = SoftwareUtil.getRunnableList(task, null); | |
/* To identify the index of the triggerEvent */ | |
final List<CallSequenceItem> callSequenceList = SoftwareUtil.collectCalls(task, null, | |
(call -> call instanceof TaskRunnableCall || call instanceof InterProcessTrigger || call instanceof ClearEvent | |
|| call instanceof SetEvent || call instanceof WaitEvent)); | |
int indexforTrigger = 0; | |
for (int i = 0; i < callSequenceList.size(); i++) { | |
if (callSequenceList.get(i) instanceof InterProcessTrigger) { | |
indexforTrigger = i; | |
} | |
} | |
/* To distinguish CPU Tasks between Sync & Async */ | |
if (isTriggeringTask(task)) { | |
/* all should be synchronous (wait should not be ignored) - active wait */ | |
if (SharedConsts.synchronousOffloading == true) { | |
result = syncTypeOperation(indexforTrigger, callSequenceList, runnableList, pu, executionCase, cpurta); | |
/* if this task has the OffloadingAsync runnable, subtract the runnable part from the result */ | |
if (doesTaskHaveAsyncRunnable(task, cpurta)) { | |
result = result.subtract(getExecutionTimeForRTARunnable(cpurta.offloadingAsyncRunnable, pu, executionCase)); | |
} | |
} | |
/* all should be asynchronous (wait should be ignored) - passive wait */ | |
else { | |
result = asyncTypeOperation(runnableList, pu, executionCase); | |
/* if this task is missing the OffloadingAsync runnable, add the runnable part to the result */ | |
if (!doesTaskHaveAsyncRunnable(task, cpurta)) { | |
result = result.add(getExecutionTimeForRTARunnable(cpurta.offloadingAsyncRunnable, pu, executionCase)); | |
} | |
} | |
} | |
else { | |
/* GPU Origin Task on CPU & No Triggering Behavior (No InterProcessTrigger) */ | |
if (!(callSequenceList.get(indexforTrigger) instanceof InterProcessTrigger)) { | |
/* GPU Origin task that is newly mapped to CPU */ | |
if (cpurta.getGpuTaskList().contains(task)) { | |
result = result.add(getExecutionTimeForGPUTaskOnCPU(task, runnableList, pu, executionCase, cpurta)); | |
result = result.add(contention); | |
return result; | |
} | |
/* No Triggering Behavior (No InterProcessTrigger) */ | |
for (final Runnable r : runnableList) { | |
result = result.add(getExecutionTimeForRTARunnable(r, pu, executionCase)); | |
} | |
} | |
} | |
result = result.add(contention); | |
return result; | |
} | |
/** | |
* Find out whether the given triggering task(that has an InterProcessTrigger) triggers a GPU task which is newly mapped to CPU. | |
* If the ProcessingUnit index of the triggered task is bigger than the biggest CPU index, that means the triggered task is mapped to GPU | |
* which would return false. | |
* @param task the observed task | |
* @param cpurta the instance of CPURta class that calls this method | |
* (to get the task List & the integer array to identify the ProcessingUnit index of the triggered task) | |
* @return | |
* boolean value (true: the observed task triggers a task that is mapped to CPU / | |
* false: the observed task triggers a task that is mapped to GPU) | |
*/ | |
private boolean doesThisTaskTriggerCPUTask(final Task task, final CPURta cpurta) { | |
if (cpurta.getTriggeringTaskList().contains(task)) { | |
final List<CallSequenceItem> callList = SoftwareUtil.collectCalls(task, null, | |
(call -> call instanceof TaskRunnableCall || call instanceof InterProcessTrigger || call instanceof ClearEvent | |
|| call instanceof SetEvent || call instanceof WaitEvent)); | |
final InterProcessStimulus ips = ((InterProcessTrigger) callList.stream().filter(s -> s instanceof InterProcessTrigger).iterator().next()) | |
.getStimulus(); | |
final EList<Task> allTaskList = cpurta.getModel().getSwModel().getTasks(); | |
final int[] ia = cpurta.getIA(); | |
final int cpuThreshold = CommonUtils.getNumberofCPUs(cpurta.getModel()) - 1; | |
for (int i = 0; i < ia.length; i++) { | |
if (ia[i] > cpuThreshold) { | |
final Task theTask = allTaskList.get(i); | |
if (theTask.getStimuli().get(0) instanceof InterProcessStimulus) { | |
final InterProcessStimulus thisIPS = (InterProcessStimulus) theTask.getStimuli().get(0); | |
if (ips.equals(thisIPS)) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("Confirmation: The triggered task mapped to (GPU)"); | |
return false; | |
} | |
} | |
} | |
} | |
Logger.getLogger(RTARuntimeUtil.class).debug("Confirmation: The triggered task mapped to (CPU)"); | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Calculate execution time of the given runnableList in a synchronous manner. | |
* (execution time of pre-processing) + GPU task response time + (execution time of post-processing) | |
* @param indexforTrigger Integer variable that is used to get InterProcessTrigger to identify the triggered GPU task | |
* @param callSequenceList callSequenceList List variable that is used to get InterProcessTrigger to identify the triggered GPU task | |
* @param runnableList the observed runnable List to calculate execution time in the synchronous mode | |
* @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @param cpurta the instance of CPURta class that calls this method | |
* (to get the identified triggered GPU task in the model) | |
* (to access to the cumuAcTime Time variable that accumulate access latency) | |
* @return | |
* synchronous execution time of the observed set | |
*/ | |
private Time syncTypeOperation(final int indexforTrigger, final List<CallSequenceItem> callSequenceList, final List<Runnable> runnableList, | |
final ProcessingUnit pu, final TimeType executionCase, final CPURta cpurta) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("TYPE: SYNC"); | |
/* set the default result time variable as 0s */ | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
/* Sum all the runnable ExecutionTime of the CPU Task */ | |
for (final Runnable r : runnableList) { | |
result = result.add(getExecutionTimeForRTARunnable(r, pu, executionCase)); | |
} | |
final InterProcessTrigger ipt = (InterProcessTrigger) callSequenceList.get(indexforTrigger); | |
final Task triggeredGPUTask = cpurta.getModel().getSwModel().getTasks().stream().filter(t -> t.getStimuli().get(0).equals(ipt.getStimulus())).iterator() | |
.next(); | |
result = result.add(cpurta.getTRT().get(triggeredGPUTask)); | |
return result; | |
} | |
/** | |
* Calculate execution time of the given runnableList in an asynchronous manner. | |
* (execution time of pre-processing) + (execution time of post-processing) | |
* @param runnableList the observed runnable List to calculate execution time in the asynchronous mode | |
* @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @return | |
* asynchronous execution time of the observed runnable List | |
*/ | |
private Time asyncTypeOperation(final List<Runnable> runnableList, final ProcessingUnit pu, final TimeType executionCase) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("TYPE: ASYNC"); | |
/** | |
* <Asynchronous Task> et_t=sum_{runnable calls before GPU trigger | |
* event}et_r + et_{runnable calls after GPU trigger event}; | |
*/ | |
/* set the default result time variable as 0s */ | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
/* Sum all the runnable ExecutionTime */ | |
for (final Runnable r : runnableList) { | |
/* In case of Pre_Detection_Post task, the AsyncOffloading runnable is already taken into account here. */ | |
result = result.add(getExecutionTimeForRTARunnable(r, pu, executionCase)); | |
} | |
return result; | |
} | |
/** | |
* Identify whether or not the given task has the OffloadingAsyncCosts Runnable (that takes costs into account in the Asynchronous mode) | |
* which some triggering tasks do not have. | |
* Since this method is used by CPURta, the visibility should be 'protected' | |
* @param task the observed task | |
* @param cpurta the instance of CPURta class that calls this method | |
* (to access to the triggeringTaskList List<Task> variable that contains tasks with an InterProcessTrigger) | |
* @return | |
* boolean value of the result | |
*/ | |
protected static boolean doesTaskHaveAsyncRunnable (final Task task, final CPURta cpurta) { | |
boolean result = false; | |
if (cpurta.getTriggeringTaskList().contains(task)) { | |
final List<CallSequenceItem> callList = SoftwareUtil.collectCalls(task, null, | |
(call -> call instanceof TaskRunnableCall || call instanceof InterProcessTrigger || call instanceof ClearEvent | |
|| call instanceof SetEvent || call instanceof WaitEvent)); | |
final int waitIndex = callList.indexOf(callList.stream().filter(s -> s instanceof WaitEvent).iterator().next()); | |
List<CallSequenceItem> clearEvent = callList.stream().filter(s -> s instanceof ClearEvent).collect(Collectors.toList()); | |
if (clearEvent.size() != 0) { | |
final int clearIndex = callList.indexOf(callList.stream().filter(s -> s instanceof ClearEvent).iterator().next()); | |
if ((clearIndex - waitIndex) > 1) { | |
result = true; | |
} | |
} | |
} else { | |
Logger.getLogger(RTARuntimeUtil.class).debug("ERROR: This task is not a triggering task!!"); | |
} | |
return result; | |
} | |
/** | |
* Calculate execution time of the given task which was originally designed for GPU but newly mapped to CPU by Generic Algorithm Mapping. | |
* It should ignore offloading runnables and take the required labels(read from pre-processing, write from post-processing) into account. | |
* The method follows Read / Compute(Ticks) / Write semantic. | |
* Read(Write)_Access_Time = Round_UP(Size_of_Read_Labels / 64.0 Bytes) * (Read_Latency / Frequency) | |
* @param task the observed task | |
* @param runnableList runnable list of the given task | |
* @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @param cpurta the instance of CPURta class that calls this method | |
* (to access to the gpuToCpuLabels HashMap variable that contains List<Label> of required read & write labels) | |
* @return | |
* execution time of the observed task | |
*/ | |
private Time getExecutionTimeForGPUTaskOnCPU(final Task task, final List<Runnable> runnableList, final ProcessingUnit pu, | |
final TimeType executionCase, final CPURta cpurta) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("TYPE: GPUTaskOnCPU // " + "Task: " + task.getName()); | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
Runnable funcRunnable = null; | |
for (final Runnable r : runnableList) { | |
final List<Ticks> thisTicksList = SoftwareUtil.getTicks(r, null); | |
if (thisTicksList.size() != 0) { | |
funcRunnable = r; | |
break; | |
} | |
} | |
final Time parameter = FactoryUtil.createTime(BigInteger.ONE, TimeUnit.S); | |
final double freq = AmaltheaServices.convertToHertz(pu.getFrequencyDomain().getDefaultValue()).longValue(); | |
final HashMap<Task, List<List<Label>>> gtcl = cpurta.getGTCL(); | |
final List<List<Label>> thisLabelList = gtcl.get(task); | |
final List<Label> readLabelList = thisLabelList.get(0); | |
final List<Label> writeLabelList = thisLabelList.get(1); | |
for (final Label l : readLabelList) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("Label(Read): " + l.getName() + " // (" + task.getName() + ")"); | |
} | |
for (final Label l : writeLabelList) { | |
Logger.getLogger(RTARuntimeUtil.class).debug("Label(Write): " + l.getName() + " // (" + task.getName() + ")"); | |
} | |
double readLatency = 0; | |
double writeLatency = 0; | |
if (executionCase.equals(TimeType.WCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getUpperBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getUpperBound(); | |
} | |
else if (executionCase.equals(TimeType.BCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getLowerBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getLowerBound(); | |
} | |
else { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getAverage(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getAverage(); | |
} | |
/* Read (LabelAccess): */ | |
double readAccessParameter = 0; | |
double sizeofReadLabels = 0; | |
for (final Label rl : readLabelList) { | |
sizeofReadLabels += rl.getSize().getNumberBytes(); | |
} | |
readAccessParameter = (Math.ceil(sizeofReadLabels / 64.0) * (readLatency / freq)); | |
final Time readAccess = parameter.multiply(readAccessParameter); | |
result = result.add(readAccess); // LabelAccess(Read) added | |
/* Execution (Ticks): */ | |
final List<Ticks> ticksList = SoftwareUtil.getTicks(funcRunnable, null); | |
for (final Ticks t : ticksList) { | |
// TODO: This line Should be replaced into below in the version 0.9.5 */ | |
final Time tickExecution = CommonUtils.getExecutionTimeForTicks(t, pu, executionCase); // 0.9.4 | |
// final Time tickExecution = RuntimeUtil.getExecutionTimeForTicks(t, pu, executionCase); // 0.9.5 | |
result = result.add(tickExecution); // Execution(Ticks) added | |
} | |
/* Write (LabelAccess): */ | |
double writeAccessParameter = 0; | |
double sizeofWriteLabels = 0; | |
for (final Label wl : writeLabelList) { | |
sizeofWriteLabels += wl.getSize().getNumberBytes(); | |
} | |
writeAccessParameter = (Math.ceil(sizeofWriteLabels / 64.0) * (writeLatency / freq)); | |
final Time writeAccess = parameter.multiply(writeAccessParameter); | |
result = result.add(writeAccess); // LabelAccess(Write) added | |
return result; | |
} | |
/** | |
* Calculate execution time of the given runnable. | |
* The method consider Read / Compute(Ticks) / Write semantic. | |
* @param runnable the observed runnable | |
* @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @return | |
* execution time of the observed runnable | |
*/ | |
private Time getExecutionTimeForRTARunnable(final Runnable runnable, final ProcessingUnit pu, final TimeType executionCase) { | |
Logger.getLogger(RTARuntimeUtil.class).debug(executionCase.toString()); | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
final double freq = AmaltheaServices.convertToHertz(pu.getFrequencyDomain().getDefaultValue()).longValue(); | |
double readLatency = 0; | |
double writeLatency = 0; | |
if (executionCase.equals(TimeType.WCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getUpperBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getUpperBound(); | |
} | |
else if (executionCase.equals(TimeType.BCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getLowerBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getLowerBound(); | |
} | |
else { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getAverage(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getAverage(); | |
} | |
/* Read & Write Memory Access Time */ | |
result = result.add(getRunnableMemoryAccessTime(runnable, freq, readLatency, writeLatency)); | |
/* Execution (Ticks): */ | |
final List<Ticks> ticksList = SoftwareUtil.getTicks(runnable, null); | |
for (final Ticks t : ticksList) { | |
// TODO: This line Should be replaced into below in the version 0.9.5 */ | |
final Time tickExecution = CommonUtils.getExecutionTimeForTicks(t, pu, executionCase); // 0.9.4 | |
// final Time tickExecution = RuntimeUtil.getExecutionTimeForTicks(t, pu, executionCase); // 0.9.5 | |
result = result.add(tickExecution); // Execution(Ticks) added | |
} | |
return result; | |
} | |
/** | |
* Calculate memory access time of the observed task. | |
* Since this method is used by CPURta, the visibility should be 'public' | |
* @param task the observed task | |
* @param pu ProcessingUnit that would compute the given runnable (A57 or Denver) | |
* @param executionCase BCET, ACET, WCET | |
* @return | |
* memory access time of the observed task | |
*/ | |
public Time getTaskMemoryAccessTime (final Task task, final ProcessingUnit pu, final TimeType executionCase) { | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
final double freq = AmaltheaServices.convertToHertz(pu.getFrequencyDomain().getDefaultValue()).longValue(); | |
final List<Runnable> runnableList = SoftwareUtil.getRunnableList(task, null); | |
double readLatency = 0; | |
double writeLatency = 0; | |
if (executionCase.equals(TimeType.WCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getUpperBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getUpperBound(); | |
} | |
else if (executionCase.equals(TimeType.BCET)) { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getLowerBound(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getLowerBound(); | |
} | |
else { | |
readLatency = pu.getAccessElements().get(0).getReadLatency().getAverage(); | |
writeLatency = pu.getAccessElements().get(0).getWriteLatency().getAverage(); | |
} | |
for(final Runnable r : runnableList ) { | |
result = result.add(getRunnableMemoryAccessTime(r, freq, readLatency, writeLatency)); | |
} | |
return result; | |
} | |
/** | |
* Calculate memory access time of the observed runnable. | |
* The method follows Read / Compute(Ticks) / Write semantic. | |
* Read(Write)_Access_Time = Round_UP(Size_of_Read_Labels / 64.0 Bytes) * (Read_Latency / Frequency) | |
* @param runnable the observed runnable | |
* @param frequency frequency value of the Processing Unit | |
* @param readLatency readLatency value of the Processing Unit | |
* @param writeLatency writeLatency value of the Processing Unit | |
* @return | |
* memory access time of the observed runnable | |
*/ | |
private Time getRunnableMemoryAccessTime (final Runnable runnable, final double frequency, | |
final double readLatency, final double writeLatency) { | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
final Time parameter = FactoryUtil.createTime(BigInteger.ONE, TimeUnit.S); | |
final List<LabelAccess> thisLAList = SoftwareUtil.getLabelAccessList(runnable, null); | |
final List<LabelAccess> readList = thisLAList.stream().filter(x -> (x.getAccess()).equals(LabelAccessEnum.READ)).collect(Collectors.toList()); | |
final List<LabelAccess> writeList = thisLAList.stream().filter(x -> (x.getAccess()).equals(LabelAccessEnum.WRITE)).collect(Collectors.toList()); | |
/* Read (LabelAccess): */ | |
double readAccessParameter = 0; | |
double sizeofReadLabels = 0; | |
for (final LabelAccess rl : readList) { | |
sizeofReadLabels += rl.getData().getSize().getNumberBytes(); | |
} | |
readAccessParameter = (Math.ceil(sizeofReadLabels / 64.0) * (readLatency / frequency)); | |
final Time readAccess = parameter.multiply(readAccessParameter); | |
result = result.add(readAccess); // LabelAccess(Read) added | |
/* Write (LabelAccess): */ | |
double writeAccessParameter = 0; | |
double sizeofWriteLabels = 0; | |
for (final LabelAccess wl : writeList) { | |
sizeofWriteLabels += wl.getData().getSize().getNumberBytes(); | |
} | |
writeAccessParameter = (Math.ceil(sizeofWriteLabels / 64.0) * (writeLatency / frequency)); | |
final Time writeAccess = parameter.multiply(writeAccessParameter); | |
result = result.add(writeAccess); // LabelAccess(Write) added | |
return result; | |
} | |
/** | |
* Identify whether the given task has an InterProcessTrigger or not. | |
* @param task the observed task | |
* @return | |
* boolean value of the result | |
*/ | |
private static boolean isTriggeringTask(final Task task) { | |
/* true: Triggering Task, false: Non-Triggering Task */ | |
boolean result = false; | |
final List<CallSequenceItem> callList = SoftwareUtil.collectCalls(task, null, | |
(call -> call instanceof TaskRunnableCall || call instanceof InterProcessTrigger || call instanceof ClearEvent | |
|| call instanceof SetEvent || call instanceof WaitEvent)); | |
List<CallSequenceItem> iptList = callList.stream().filter(s -> s instanceof InterProcessTrigger).collect(Collectors.toList()); | |
if (iptList.size() != 0) { | |
result = true; | |
} | |
return result; | |
} | |
/******************************************* Implicit Communication Paradigm *************************************************/ | |
/** | |
* For the implicit communication paradigm | |
* Time[0] = copy-in time for the observed task, Time[1] = copy-out time for the observed task | |
* if a GPU task mapped to CPU is passed here, we also need to consider its required labels from Pre-Pro processing runnables | |
* @param task the observed task | |
* @param pu the processing unit that the observed task is mapped to | |
* @param executionCase WCET, BCET, ACET | |
* @return | |
* Time array that contains copy-in, copy-out time of the observed task | |
*/ | |
public Time[] getLocalCopyTimeArray(final Task task, final ProcessingUnit pu, final TimeType executionCase, final CPURta cpurta) { | |
Time[] ta = new Time[2]; | |
Time readCopy = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
Time writeCopy = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
/* The observed task is a GPU task */ | |
if (cpurta.getGpuTaskList().contains(task)) { | |
final HashMap<Task, List<List<Label>>> gtcl = cpurta.getGTCL(); | |
final List<List<Label>> thisLabelList = gtcl.get(task); | |
final List<Label> readLabels = thisLabelList.get(0); | |
final List<Label> writeLabels = thisLabelList.get(1); | |
for (final Label rl : readLabels) { | |
readCopy = readCopy.add(getCopyEngineTime(rl, pu, executionCase, true)); | |
} | |
ta[0] = readCopy; | |
for (final Label wl : writeLabels) { | |
writeCopy = writeCopy.add(getCopyEngineTime(wl, pu, executionCase, false)); | |
} | |
ta[1] = writeCopy; | |
return ta; | |
} | |
/* The observed task is a CPU task */ | |
final List<Runnable> runnableList = SoftwareUtil.getRunnableList(task, null); | |
final List<Label> readList = new ArrayList<Label>(); | |
final List<Label> writeList = new ArrayList<Label>(); | |
for (int i = 0; i < runnableList.size(); i++) { | |
final Runnable runnable = runnableList.get(i); | |
final List<LabelAccess> laList = SoftwareUtil.getLabelAccessList(runnable, null); | |
final List<Label> rList = laList.stream().filter(s -> (s.getAccess()).equals(LabelAccessEnum.READ)) | |
.map(s->s.getData()).collect(Collectors.toList()); | |
rList.stream().forEach(s -> readList.add(s)); | |
final List<Label> wList = laList.stream().filter(s -> (s.getAccess()).equals(LabelAccessEnum.WRITE)) | |
.map(s->s.getData()).collect(Collectors.toList()); | |
wList.stream().forEach(s -> writeList.add(s)); | |
} | |
final List<Label> readLabels = readList.stream().distinct().collect(Collectors.toList()); | |
final List<Label> writeLabels = writeList.stream().distinct().collect(Collectors.toList()); | |
for (final Label rl : readLabels) { | |
readCopy = readCopy.add(getCopyEngineTime(rl, pu, executionCase, true)); | |
} | |
ta[0] = readCopy; | |
for (final Label wl : writeLabels) { | |
writeCopy = writeCopy.add(getCopyEngineTime(wl, pu, executionCase, false)); | |
} | |
ta[1] = writeCopy; | |
return ta; | |
} | |
/** | |
* The method is used to calculate CopyEngine time for single label. | |
* @param label the observed label | |
* @param pu ProcessingUnit that would process the given label | |
* @param executionCase BCET, ACET, WCET | |
* @param readOrWrite when the given runnable is 'runnable_0'(the first callSquence of the task), it is read(true), | |
* when the given runnable is 'runnable_Last'(the last callSquence of the task), it is write(false). | |
* @return | |
* the given label copy engine time | |
*/ | |
private Time getCopyEngineTime(final Label label, final ProcessingUnit pu, final TimeType executionCase, final boolean readOrWrite) { | |
Time result = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); | |
final Time parameter = FactoryUtil.createTime(BigInteger.ONE, TimeUnit.S); | |
final double freq = AmaltheaServices.convertToHertz(pu.getFrequencyDomain().getDefaultValue()).longValue(); | |
double latency = 0; | |
/* Read */ | |
if(readOrWrite) { | |
if (executionCase.equals(TimeType.BCET)) { | |
latency = pu.getAccessElements().get(0).getReadLatency().getLowerBound(); | |
} else if (executionCase.equals(TimeType.ACET)) { | |
latency = pu.getAccessElements().get(0).getReadLatency().getAverage(); | |
} else if (executionCase.equals(TimeType.WCET)) { | |
latency = pu.getAccessElements().get(0).getReadLatency().getUpperBound(); | |
} | |
} | |
/* Write */ | |
else { | |
if (executionCase.equals(TimeType.BCET)) { | |
latency = pu.getAccessElements().get(0).getWriteLatency().getLowerBound(); | |
} else if (executionCase.equals(TimeType.ACET)) { | |
latency = pu.getAccessElements().get(0).getWriteLatency().getAverage(); | |
} else if (executionCase.equals(TimeType.WCET)) { | |
latency = pu.getAccessElements().get(0).getWriteLatency().getUpperBound(); | |
} | |
} | |
double labelAccessParameter = 0; | |
final double labelSize = label.getSize().getNumberBytes(); | |
labelAccessParameter = (Math.ceil(labelSize / 64.0) * (latency / freq)); | |
final Time labelAccess = parameter.multiply(labelAccessParameter); | |
result = result.add(labelAccess); // LabelAccess(Read) added | |
return result; | |
} | |
} |