| /******************************************************************************* |
| * 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.BufferedWriter; |
| import java.io.FileOutputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.Writer; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map.Entry; |
| import java.util.Scanner; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| import org.apache.log4j.Logger; |
| import org.eclipse.app4mc.amalthea.model.Amalthea; |
| import org.eclipse.app4mc.amalthea.model.AmaltheaFactory; |
| import org.eclipse.app4mc.amalthea.model.AmaltheaServices; |
| import org.eclipse.app4mc.amalthea.model.CallSequence; |
| import org.eclipse.app4mc.amalthea.model.CallSequenceItem; |
| import org.eclipse.app4mc.amalthea.model.DiscreteValueConstant; |
| import org.eclipse.app4mc.amalthea.model.DiscreteValueStatistics; |
| import org.eclipse.app4mc.amalthea.model.ExecutionNeed; |
| import org.eclipse.app4mc.amalthea.model.Frequency; |
| import org.eclipse.app4mc.amalthea.model.GraphEntryBase; |
| import org.eclipse.app4mc.amalthea.model.HwDefinition; |
| import org.eclipse.app4mc.amalthea.model.IDiscreteValueDeviation; |
| 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.MappingModel; |
| import org.eclipse.app4mc.amalthea.model.PeriodicStimulus; |
| import org.eclipse.app4mc.amalthea.model.ProcessingUnit; |
| import org.eclipse.app4mc.amalthea.model.ProcessingUnitDefinition; |
| import org.eclipse.app4mc.amalthea.model.PuType; |
| import org.eclipse.app4mc.amalthea.model.Runnable; |
| import org.eclipse.app4mc.amalthea.model.RunnableItem; |
| import org.eclipse.app4mc.amalthea.model.SchedulerAllocation; |
| import org.eclipse.app4mc.amalthea.model.Stimulus; |
| import org.eclipse.app4mc.amalthea.model.Task; |
| import org.eclipse.app4mc.amalthea.model.TaskAllocation; |
| 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.UserSpecificSchedulingAlgorithm; |
| import org.eclipse.app4mc.amalthea.model.util.DeploymentUtil; |
| import org.eclipse.app4mc.amalthea.model.util.FactoryUtil; |
| import org.eclipse.app4mc.amalthea.model.util.HardwareUtil; |
| import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil; |
| import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType; |
| import org.eclipse.app4mc.amalthea.model.util.SoftwareUtil; |
| |
| public class CommonUtils { |
| |
| /** |
| * @param amalthea Amalthea model |
| * @return List of processing units which CPUs at the beginning (GPUs at the end) |
| */ |
| public static List<ProcessingUnit> getPUs(final Amalthea amalthea) { |
| final List<ProcessingUnit> pul = new ArrayList<ProcessingUnit>(); |
| for (final HwDefinition hwd : amalthea.getHwModel().getDefinitions()) { |
| if (hwd instanceof ProcessingUnitDefinition) { |
| final ProcessingUnitDefinition pud = (ProcessingUnitDefinition) hwd; |
| if (pud.getPuType().equals(PuType.CPU)) { |
| /* insert at the beginning */ |
| pul.addAll(0, HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(amalthea, pud)); |
| } |
| else { |
| pul.addAll(HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(amalthea, pud)); |
| } |
| } |
| } |
| return pul; |
| } |
| |
| /* UTIL Classes SoftwareUtil.getAccessedLabelSet(t, null) not Wokring => this method works */ |
| /** |
| * @param t Task |
| * @return Labels accessed by Task t |
| */ |
| public static Set<Label> getAccessedLabelSet(final Task t) { |
| final Set<Label> ls = new HashSet<Label>(); |
| for (final GraphEntryBase geb : t.getCallGraph().getGraphEntries()) { |
| if (geb instanceof CallSequence) { |
| final CallSequence cs = (CallSequence) geb; |
| for (final CallSequenceItem csi : cs.getCalls()) { |
| if (csi instanceof TaskRunnableCall) { |
| final TaskRunnableCall trc = (TaskRunnableCall) csi; |
| final Runnable r = trc.getRunnable(); |
| for (final RunnableItem ri : r.getRunnableItems()) { |
| if (ri instanceof LabelAccess) { |
| final LabelAccess la = (LabelAccess) ri; |
| ls.add(la.getData()); |
| } |
| } |
| } |
| } |
| } |
| } |
| return ls; |
| } |
| |
| /** |
| * @param model Amalthea |
| * @return integer array size of tasks, that contains processing unit indexes |
| * for each task for the processing unit the tasks are mapped to according to |
| * the task allocation entries in the mapping model |
| */ |
| public static int[] getIAFromMappingModel(final Amalthea model) { |
| final int[] ia = new int[model.getSwModel().getTasks().size()]; |
| final List<ProcessingUnit> pul = CommonUtils.getPUs(model); |
| for (final TaskAllocation ta : model.getMappingModel().getTaskAllocation()) { |
| final Task t = ta.getTask(); |
| final ProcessingUnit pu = ta.getAffinity().get(0); |
| ia[model.getSwModel().getTasks().indexOf(t)] = pul.indexOf(pu); |
| } |
| return ia; |
| } |
| |
| /** |
| * @param model Amalthea model |
| * @return HashMap<Task,Time> which contains a timeslice for each task if there exists task |
| * allocation entities within the mapping model with "timeslice" parameter extensions for each task |
| */ |
| public static HashMap<Task, Time> getTimeSlices(final Amalthea model) { |
| final HashMap<Task, Time> ret = new HashMap<>(); |
| final Logger log = Logger.getLogger(CommonUtils.class); |
| if (!SharedConsts.useModelTimeSlices) { |
| final List<ProcessingUnit> pul = getPUs(model); |
| final ProcessingUnit gpu = pul.get(pul.size() - 1); |
| final List<Task> tl = getGPUTasksOrderedByRecurrence(model); |
| //model.getMappingModel().getTaskAllocation().stream().filter(ta->ta.getAffinity().get(0).getDefinition().getPuType().equals(PuType.GPU)).map(ta->ta.getTask()).collect(Collectors.toList()); |
| for (final Task t : tl) { |
| long tsl = SharedConsts.timeSliceLengthPS; |
| switch (SharedConsts.tsDeriv) { |
| case TS: |
| break; |
| case TSxPrio: |
| tsl = tsl * (tl.size() - tl.indexOf(t)); |
| break; |
| case TSxUtil: |
| final double util = getET(t, gpu, SharedConsts.timeType).divide(getStimInTime(t)); |
| tsl = (long) (util * SharedConsts.timeSliceLengthPS); |
| break; |
| case TSxUtilxNbTasks: |
| final double util2 = getET(t, gpu, SharedConsts.timeType).divide(getStimInTime(t)); |
| tsl = (long) (util2 * tl.size() * SharedConsts.timeSliceLengthPS); |
| break; |
| default: |
| break; |
| } |
| final Time time = FactoryUtil.createTime(tsl, TimeUnit.PS).adjustUnit(); |
| ret.put(t, time); |
| } |
| ret.entrySet().stream().forEach(es -> log.debug("TimeSlices: " + es.getKey().getName() + " " + es.getValue().toString() + "; ")); |
| return ret; |
| } |
| if (null == model.getOsModel()) { |
| log.error("No OS Model"); |
| return null; |
| } |
| if (model.getOsModel().getOperatingSystems().size() < 1) { |
| log.error("No Operating System"); |
| return null; |
| } |
| if (model.getOsModel().getOperatingSystems().get(0).getTaskSchedulers().size() < 1) { |
| log.error("No Task Scheduler in Operating System"); |
| return null; |
| } |
| if (null == model.getMappingModel()) { |
| log.error("No Mapping Model"); |
| return null; |
| } |
| if (null == model.getMappingModel().getSchedulerAllocation()) { |
| log.error("No Scheduler Allocations"); |
| return null; |
| } |
| if (null == model.getMappingModel().getTaskAllocation()) { |
| log.error("No Task Allocations"); |
| return null; |
| } |
| for (final SchedulerAllocation sa : model.getMappingModel().getSchedulerAllocation()) { |
| if (sa.getScheduler().getSchedulingAlgorithm() instanceof UserSpecificSchedulingAlgorithm) { |
| final UserSpecificSchedulingAlgorithm ussa = (UserSpecificSchedulingAlgorithm) sa.getScheduler().getSchedulingAlgorithm(); |
| final List<Entry<String, String>> pel = ussa.getParameterExtensions().stream().collect(Collectors.toList()); |
| final Time[] ta = new Time[2]; |
| for (final Entry<String, String> e : pel) { |
| if (e.getKey().toString().contains("minimumTimeslice")) { |
| final Time mints = parseTimeString(e.getValue().toString()); |
| ta[0] = mints; |
| } |
| else if (e.getKey().toString().contains("maximumTimeslice")) { |
| final Time maxts = parseTimeString(e.getValue().toString()); |
| ta[1] = maxts; |
| } |
| else if (e.getKey().toString().contains("Timeslice")) { |
| final Time constts = parseTimeString(e.getValue().toString()); |
| ta[0] = constts; |
| } |
| } |
| final List<TaskAllocation> tsal = model.getMappingModel().getTaskAllocation().stream() |
| .filter(tal -> tal.getScheduler() != null && tal.getScheduler().equals(sa.getScheduler())).collect(Collectors.toList()); |
| if (tsal.size() > 0) { |
| final TaskAllocation tsa = tsal.get(0); |
| Time time = ta[0]; |
| if (null != ta[1]) { |
| /*TODO handle min max*/ |
| /*setting time to average*/ |
| time = time.add(ta[1]); |
| time.setValue(time.getValue().divide(BigInteger.valueOf(2))); |
| } |
| ret.put(tsa.getTask(), time); |
| } |
| } |
| } |
| for (final TaskAllocation ta : model.getMappingModel().getTaskAllocation()) { |
| for (final Entry<String, String> e : ta.getParameterExtensions()) { |
| if (e.getKey().contains("timeslice") || e.getKey().contains("TimeSlice") || e.getKey().contains("Timeslice")) { |
| if (!ret.containsKey(ta.getTask())) { |
| ret.put(ta.getTask(), parseTimeString(e.getValue())); |
| } |
| } |
| } |
| } |
| final StringBuffer sb = new StringBuffer(); |
| ret.entrySet().stream().forEach(es -> sb.append("TimeSlices: " + es.getKey().getName() + " " + es.getValue().toString() + "; ")); |
| log.debug(sb); |
| return ret; |
| } |
| |
| /** |
| * @param task |
| * @param model |
| * @return Time of timeslice, if there exists a taskAllocation for the task, which a parameterExtension with key "timeslice" |
| */ |
| public static Time getTimeSlice(final Task task, final Amalthea model) { |
| Entry<String, String> pex = null; |
| for (final TaskAllocation ta : model.getMappingModel().getTaskAllocation()) { |
| if (ta.getTask().equals(task)) { |
| for (final Entry<String, String> e : ta.getParameterExtensions()) { |
| if (e.getKey().contains("timeslice") || e.getKey().contains("TimeSlice") || e.getKey().contains("Timeslice")) { |
| pex = e; |
| } |
| } |
| } |
| } |
| |
| if (null == pex) { |
| // final Time sum = getTimeSlices(model).get(task)[0].add(getTimeSlices(model).get(task)[1]); |
| // final Time two = FactoryUtil.createTime(2, sum.getUnit()); |
| // return FactoryUtil.createTime(BigInteger.valueOf((long) sum.divide(two)), sum.getUnit()); |
| return getTimeSlices(model).get(task); |
| } |
| return parseTimeString(pex.getValue()); |
| } |
| |
| |
| /** |
| * @param string should contain a number and a unit |
| * @return String as Time, e.g. "12ms" => Time.value=12; Time.unit=TimeUnit.MS; |
| */ |
| private static Time parseTimeString(final String string) { |
| final Time time = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| @SuppressWarnings("resource") |
| final Scanner sc = new Scanner(string); |
| time.setValue(BigInteger.valueOf(sc.useDelimiter("[^0-9]+").nextInt())); |
| switch (string.substring(string.length() - 2, string.length())) { |
| case " s": |
| time.setUnit(TimeUnit.S); |
| break; |
| case "ms": |
| time.setUnit(TimeUnit.MS); |
| break; |
| case "us": |
| time.setUnit(TimeUnit.US); |
| break; |
| case "ns": |
| time.setUnit(TimeUnit.NS); |
| break; |
| case "ps": |
| time.setUnit(TimeUnit.PS); |
| break; |
| default: |
| time.setUnit(TimeUnit._UNDEFINED_); |
| } |
| return time; |
| } |
| |
| /** |
| * @param t Task |
| * @param amalthea Model |
| * @return Time execution time based on DeploymentUtil.getAssignedCoreForProcess |
| */ |
| public static Time getSimpleET(final Task t, final Amalthea amalthea) { |
| final Time time = CommonUtils.getET(t, DeploymentUtil.getAssignedCoreForProcess(t, amalthea).iterator().next(), SharedConsts.timeType); |
| return time; |
| } |
| |
| /** |
| * @param t Task |
| * @param pu Processing Unit |
| * @return Time execution time of t at pu |
| */ |
| public static Time getET(final Task t, final ProcessingUnit pu, final TimeType tt) { |
| Time ct = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| for (final ExecutionNeed en : SoftwareUtil.getExecutionNeeds(t, null)) { |
| for (final Entry<String, IDiscreteValueDeviation> needs : en.getNeeds().entrySet()) { |
| ct = ct.add(RuntimeUtil.getExecutionTimeForExecutionNeedEntry(needs.getValue(), null, pu, SharedConsts.timeType)); |
| } |
| } |
| for (final Ticks ticks : SoftwareUtil.getTicks(t, null)) { |
| /* considers extended */ |
| ct = ct.add(getExecutionTimeForTicks(ticks, pu, tt)); |
| } |
| if (ct.getValue().toString().endsWith("999")) { |
| ct.setValue(ct.getValue().add(BigInteger.ONE)); |
| } |
| return ct; |
| } |
| |
| /*--------------------------------------BEGIN COPY FROM RUNTIMEUTIL------------------------------------------------*/ |
| /** |
| * FIX for APP4MC0.9.4 only |
| * @param ticks |
| * @param pu |
| * @param tt |
| * @return Time execution time for a given Ticks value derived from given ProcessingUnit and TimeType |
| */ |
| public static Time getExecutionTimeForTicks(final Ticks ticks, final ProcessingUnit pu, final TimeType tt) { |
| Time result = FactoryUtil.createTime(); |
| |
| if (ticks.getExtended().get(pu.getDefinition()) != null) { |
| final IDiscreteValueDeviation deviation = ticks.getExtended().get(pu.getDefinition()); |
| result = getExecutionTimeForTicksDeviation(deviation, pu, tt); |
| } |
| else { |
| result = getExecutionTimeForTicksDeviation(ticks.getDefault(), pu, tt); |
| } |
| return result; |
| } |
| |
| /** |
| * FIX for APP4MC0.9.4 only |
| * @param deviation |
| * @param pu |
| * @param tt |
| * @return Time execution time for a given IDiscreteValueDeviation value derived from given ProcessingUnit and TimeType |
| */ |
| private static Time getExecutionTimeForTicksDeviation(final IDiscreteValueDeviation deviation, final ProcessingUnit pu, final TimeType tt) { |
| double ticks = 0d; |
| switch (tt) { |
| case BCET: |
| ticks = deviation.getLowerBound().doubleValue(); |
| break; |
| case ACET: |
| ticks = deviation.getAverage(); |
| break; |
| case WCET: |
| ticks = deviation.getUpperBound().doubleValue(); |
| break; |
| } |
| final Time result = getExecutionTimeForCycles(ticks, pu.getFrequencyDomain().getDefaultValue()); |
| return result; |
| } |
| |
| /** |
| * FIX for APP4MC0.9.4 only |
| * @param ticks Double |
| * @param frequency |
| * @return Time execution time for a given double value derived from the frequency |
| */ |
| public static Time getExecutionTimeForCycles(final double ticks, final Frequency frequency) { |
| final double cyclesPerSecond = AmaltheaServices.convertToHertz(frequency).doubleValue(); |
| final double factor = 1.0d / cyclesPerSecond; |
| final Time oneSecond = FactoryUtil.createTime(1, TimeUnit.S); |
| final Time t1 = oneSecond.multiply(ticks); |
| final Time result = t1.multiply(factor); |
| return result.adjustUnit(); |
| } |
| /*--------------------------------------END COPY FROM RUNTIMEUTIL------------------------------------------------*/ |
| |
| /** |
| * @param amalthea Amalthea model |
| * @param onlyGPUStim optional boolean parameter whether only GPU Stimuli should be accounted |
| * @return ordered list of stimuli; index 0 = lowest recurrence value |
| */ |
| public static List<PeriodicStimulus> getSortedStim(final Amalthea amalthea, final boolean... onlyGPUStim) { |
| final List<PeriodicStimulus> stimListSorted = new ArrayList<PeriodicStimulus>(); |
| List<Task> tl = null; |
| if (null != onlyGPUStim && onlyGPUStim[0]) { |
| tl = amalthea.getMappingModel().getTaskAllocation().stream().filter(ta -> ta.getAffinity().get(0).getDefinition().getPuType().equals(PuType.GPU)) |
| .map(ta -> ta.getTask()).collect(Collectors.toList()); |
| } |
| for (final Stimulus s : amalthea.getStimuliModel().getStimuli()) { |
| if (s instanceof PeriodicStimulus) { |
| final PeriodicStimulus ps = (PeriodicStimulus) s; |
| if (null != onlyGPUStim && onlyGPUStim[0] && null != tl) { |
| for (final Task t : tl) { |
| if (t.getStimuli().contains(ps) && !stimListSorted.contains(ps)) { |
| stimListSorted.add(ps); |
| break; |
| } |
| } |
| } |
| else { |
| stimListSorted.add(ps); |
| } |
| } |
| } |
| Collections.sort(stimListSorted, (a, b) -> a.getRecurrence().compareTo(b.getRecurrence())); |
| return stimListSorted; |
| } |
| |
| /** |
| * @param t Task |
| * @return time recurrence if task @param t is periodically called or interProcess triggered, |
| * i.e., the recurrence of the triggering task is returned; |
| * Otherwise time 0 is returned |
| */ |
| public static Time getStimInTime(final Task t) { |
| final Logger log = Logger.getLogger(CommonUtils.class); |
| if (t.getStimuli().size() > 1) { |
| // TODO |
| log.warn("Multiple Simuli not supported."); |
| } |
| for (final Stimulus s : t.getStimuli()) { |
| if (s instanceof PeriodicStimulus) { |
| final PeriodicStimulus ps = (PeriodicStimulus) s; |
| return ps.getRecurrence(); |
| } |
| if (s instanceof InterProcessStimulus) { |
| final InterProcessStimulus ips = (InterProcessStimulus) s; |
| // final List<Process> triggers = ips.getExplicitTriggers().stream().map(ipt -> ipt.getContainingProcess()).collect(Collectors.toList()); |
| // final Time rec = ((PeriodicStimulus) triggers.get(0).getStimuli().get(0)).getRecurrence(); |
| final Task trigger = getFirstTrigger(ips); |
| return ((PeriodicStimulus) trigger.getStimuli().get(0)).getRecurrence(); |
| } |
| log.warn("Stimuli other than periodic / interprocesstrigger not supported."); |
| } |
| return FactoryUtil.createTime(0, TimeUnit._UNDEFINED_); |
| } |
| |
| /** |
| * Logs mutliple stimuli / stimuli != (Periodic,InterProcessTrigger) |
| * @param t Task |
| * @return PeriodicStimulus of Task t |
| */ |
| public static PeriodicStimulus getStim(final Task t) { |
| final Logger log = Logger.getLogger(CommonUtils.class); |
| if (t.getStimuli().size() > 1) { |
| // TODO |
| log.warn("Multiple Simuli not supported."); |
| } |
| for (final Stimulus s : t.getStimuli()) { |
| if (s instanceof PeriodicStimulus) { |
| final PeriodicStimulus ps = (PeriodicStimulus) s; |
| return ps; |
| } |
| if (s instanceof InterProcessStimulus) { |
| final InterProcessStimulus ips = (InterProcessStimulus) s; |
| // final List<Process> triggers = ips.getExplicitTriggers().stream().map(ipt -> ipt.getContainingProcess()).collect(Collectors.toList()); |
| // final Time rec = ((PeriodicStimulus) triggers.get(0).getStimuli().get(0)).getRecurrence(); |
| final Task trigger = getFirstTrigger(ips); |
| return ((PeriodicStimulus) trigger.getStimuli().get(0)); |
| } |
| log.warn("Stimuli other than periodic / interprocesstrigger not supported."); |
| } |
| log.error("NO SUPPORTED STIMULUS"); |
| return null; |
| } |
| |
| /** |
| * @param ips InterProcessStimulus |
| * @return Task t that contains ips as activation |
| */ |
| private static Task getFirstTrigger(final InterProcessStimulus ips) { |
| final Amalthea model = (Amalthea) ips.eContainer().eContainer(); |
| for (final Task t : model.getSwModel().getTasks()) { |
| for (final GraphEntryBase geb : t.getCallGraph().getGraphEntries()) { |
| if (geb instanceof CallSequence) { |
| final CallSequence cs = (CallSequence) geb; |
| for (final CallSequenceItem csi : cs.getCalls()) { |
| if (csi instanceof InterProcessTrigger) { |
| final InterProcessTrigger ipt = (InterProcessTrigger) csi; |
| if (ipt.getStimulus().equals(ips)) { |
| return t; |
| } |
| } |
| } |
| } |
| } |
| } |
| final Logger log = Logger.getLogger("CommonUtils"); |
| log.error("No triggering task found for " + ips.getName()); |
| return null; |
| } |
| |
| /** |
| * requires mapping model within the given AMALTHEA model. Prints all task acllocations into log. |
| * @param amalthea Model |
| */ |
| public void printTaskAllocs(final Amalthea amalthea) { |
| final Logger log = Logger.getLogger(this.getClass().getName().substring(this.getClass().getName().lastIndexOf("." + 1))); |
| for (final TaskAllocation ta : amalthea.getMappingModel().getTaskAllocation()) { |
| log.debug(" " + Thread.currentThread().getId() + " " + ta.getTask().getName() + " ==> " + ta.getAffinity().get(0).getName()); |
| } |
| } |
| |
| /** |
| * @param am Amalthea model |
| * @param ia Task to processing unit mapping int array |
| * @return ordered List of tasks mapped to GPUs, lowest recurrence (period) at beginning |
| */ |
| public static List<Task> getGPUTasksOrderedByRecurrence(final Amalthea am, final int[]... ia) { |
| List<Task> tl = am.getMappingModel().getTaskAllocation().stream().filter(ta -> ta.getAffinity().get(0).getDefinition().getPuType().equals(PuType.GPU)) |
| .map(ta -> ta.getTask()).collect(Collectors.toList()); |
| if (ia.length > 0) { |
| final int[] mapping = ia[0]; |
| final List<Integer> il = new ArrayList<Integer>(); |
| final List<ProcessingUnit> gpus = getPUs(am); |
| for (final ProcessingUnit pu : gpus) { |
| if (pu.getDefinition().getPuType().equals(PuType.GPU)) { |
| il.add(gpus.indexOf(pu)); |
| } |
| } |
| /*il = only indexes of GPUs*/ |
| final List<Task> gpuTasks = new ArrayList<Task>(); |
| for (int i = 0; i < mapping.length; i++) { |
| if (il.contains(mapping[i])) { |
| /*task i is mapped tp a GPU*/ |
| gpuTasks.add(am.getSwModel().getTasks().get(i)); |
| } |
| } |
| tl = gpuTasks; |
| } |
| tl.sort(new Comparator<Task>() { |
| @Override |
| public int compare(final Task t1, final Task t2) { |
| final List<Stimulus> psl1 = t1.getStimuli().stream().filter(s -> s instanceof PeriodicStimulus).collect(Collectors.toList()); |
| final List<Stimulus> psl2 = t2.getStimuli().stream().filter(s -> s instanceof PeriodicStimulus).collect(Collectors.toList()); |
| if (psl1.size() != 1 || psl2.size() != 1) { |
| Logger.getLogger("CommonUtils").debug("Task " + t1.getName() + " has no periodic stimulus."); |
| return 0; |
| } |
| return ((PeriodicStimulus) psl1.get(0)).getRecurrence().compareTo(((PeriodicStimulus) psl2.get(0)).getRecurrence()); |
| } |
| }); |
| return tl; |
| } |
| |
| /** single core schedulability => utilization must be <= 1*/ |
| public static boolean isSchedulable(final List<Task> tl, final ProcessingUnit pu) { |
| Double sum = 0d; |
| for (final Task t : tl) { |
| final Time et = CommonUtils.getET(t, pu, SharedConsts.timeType); |
| final Time per = getStimInTime(t); |
| sum += et.divide(per); |
| } |
| return sum > 1 ? false : true; |
| } |
| |
| /** Creates a Mapping Model from an integer array */ |
| public static MappingModel createMMFromIA(final Amalthea amalthea, final int[] ia) { |
| final List<ProcessingUnit> pul = getPUs(amalthea); |
| final MappingModel mm = AmaltheaFactory.eINSTANCE.createMappingModel(); |
| for (int i = 0; i < amalthea.getSwModel().getTasks().size(); i++) { |
| final TaskAllocation ta = AmaltheaFactory.eINSTANCE.createTaskAllocation(); |
| ta.setTask(amalthea.getSwModel().getTasks().get(i)); |
| ta.getAffinity().add(pul.get(ia[i])); |
| mm.getTaskAllocation().add(ta); |
| } |
| return mm; |
| } |
| |
| /** |
| * @param model |
| * @return int number of GPUs |
| */ |
| public static int getNumberofGPUs(final Amalthea model) { |
| int gpus = 0; |
| for (final HwDefinition hwd : model.getHwModel().getDefinitions()) { |
| if (hwd instanceof ProcessingUnitDefinition) { |
| final ProcessingUnitDefinition pud = (ProcessingUnitDefinition) hwd; |
| if (pud.getPuType().equals(PuType.GPU)) { |
| gpus += HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(model, pud).size(); |
| } |
| } |
| } |
| return gpus; |
| } |
| |
| /** |
| * @param amalthea |
| * @return int number of CPUs |
| */ |
| public static int getNumberofCPUs(final Amalthea amalthea) { |
| int cpus = 0; |
| for (final HwDefinition hwd : amalthea.getHwModel().getDefinitions()) { |
| if (hwd instanceof ProcessingUnitDefinition) { |
| final ProcessingUnitDefinition pud = (ProcessingUnitDefinition) hwd; |
| if (pud.getPuType().equals(PuType.CPU)) { |
| cpus += HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(amalthea, pud).size(); |
| } |
| } |
| } |
| return cpus; |
| } |
| |
| /** |
| * @param amalthea Model |
| * @return int number of processing units |
| */ |
| public static int getNumberofPUs(final Amalthea amalthea) { |
| int pus = 0; |
| |
| for (final HwDefinition hwd : amalthea.getHwModel().getDefinitions()) { |
| if (hwd instanceof ProcessingUnitDefinition) { |
| final ProcessingUnitDefinition pud = (ProcessingUnitDefinition) hwd; |
| if (pud.getPuType().equals(PuType.CPU)) { |
| /* insert at the beginning */ |
| pus += HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(amalthea, pud).size(); |
| } |
| else { |
| pus += HardwareUtil.getAllProcessingUnitsForProcessingUnitDefinition(amalthea, pud).size(); |
| } |
| } |
| } |
| return pus; |
| } |
| |
| @SuppressWarnings("resource") |
| /** writes a stringbuffer into either measurements.csv or optional @param filename */ |
| public static void writeCSV(final StringBuffer sbp, final String... filenamep) { |
| if (null == sbp) { |
| Logger.getLogger(CommonUtils.class).error("Nothing to write. Probably, the system is not schedulable."); |
| return; |
| } |
| String fileName; |
| if (null != filenamep && filenamep.length > 0 && null != filenamep[0]) { |
| fileName = filenamep[0]; |
| } |
| else { |
| fileName = "measurements.csv"; |
| } |
| try { |
| final Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), "utf-8")); |
| writer.write(sbp.toString()); |
| writer.close(); |
| System.out.println("Wrote results to " + System.getProperty("user.dir") + "/" + fileName); |
| } |
| catch (final Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| /** |
| * @param model Amalthea model |
| * @param ia Task to Processingunit integer array |
| * @param t Task to be checked |
| * @return Time sum of execution times of all triggered tasks of t |
| */ |
| public static Time getETofTriggeredTask(final Amalthea model, final int[] ia, final Task t) { |
| Time time = FactoryUtil.createTime(BigInteger.ZERO, TimeUnit.PS); |
| final List<InterProcessTrigger> ipts = getTriggered(t); |
| final List<ProcessingUnit> pul = CommonUtils.getPUs(model); |
| /*task triggers other task*/ |
| for (final InterProcessTrigger ipt : ipts) { |
| final List<Task> triggered = model.getSwModel().getTasks().stream().filter(task -> task.getStimuli().get(0).equals(ipt.getStimulus())) |
| .collect(Collectors.toList()); |
| for (final Task task : triggered) { |
| final ProcessingUnit pu = pul.get(ia[model.getSwModel().getTasks().indexOf(task)]); |
| time = time.add(CommonUtils.getET(task, pu, TimeType.WCET)); |
| } |
| } |
| return time; |
| } |
| |
| /** |
| * @param ama Amalthea model |
| * @param t Task to be checked |
| * @return List of tasks triggered by t via interProcessTrigger event contained in t |
| */ |
| public static List<Task> getTriggeredTasks(final Amalthea ama, final Task t) { |
| final List<Task> tl = new ArrayList<>(); |
| final List<InterProcessTrigger> ipts = getTriggered(t); |
| /*task triggers other task*/ |
| for (final InterProcessTrigger ipt : ipts) { |
| tl.addAll(ama.getSwModel().getTasks().stream().filter(task -> task.getStimuli().get(0).equals(ipt.getStimulus())).collect(Collectors.toList())); |
| } |
| return tl; |
| } |
| |
| /** |
| * @param pu Processing Unit |
| * @param t Task |
| * @return Ticks of t at pu |
| */ |
| public static long getTicksLongForPU(final ProcessingUnit pu, final Task t) { |
| long sum = 0; |
| for (final Ticks ticks : SoftwareUtil.getTicks(t, null)) { |
| if (null != ticks && null != ticks.getExtended() && null != ticks.getExtended().get(pu.getDefinition())) { |
| |
| if (null != ticks.getExtended().get(pu.getDefinition())) { |
| if (ticks.getExtended().get(pu.getDefinition()) instanceof DiscreteValueConstant) { |
| sum += ((DiscreteValueConstant) ticks.getExtended().get(pu.getDefinition())).getValue(); |
| } |
| else if (ticks.getExtended().get(pu.getDefinition()) instanceof DiscreteValueStatistics) { |
| final DiscreteValueStatistics dvs = (DiscreteValueStatistics) ticks.getExtended().get(pu.getDefinition()); |
| sum += (dvs.getLowerBound() + dvs.getUpperBound()) / 2; |
| } |
| } |
| else { |
| sum += ((DiscreteValueConstant) ticks.getDefault()).getValue(); |
| } |
| } |
| } |
| return sum; |
| } |
| |
| /** |
| * @param t |
| * @return List of interProcessTriggers of Task t |
| */ |
| public static List<InterProcessTrigger> getTriggered(final Task t) { |
| final List<InterProcessTrigger> iptl = new ArrayList<>(); |
| for (final GraphEntryBase geb : t.getCallGraph().getGraphEntries()) { |
| if (geb instanceof CallSequence) { |
| final CallSequence cs = (CallSequence) geb; |
| for (final CallSequenceItem csi : cs.getCalls()) { |
| if (csi instanceof InterProcessTrigger) { |
| final InterProcessTrigger ipt = (InterProcessTrigger) csi; |
| iptl.add(ipt); |
| } |
| } |
| } |
| } |
| return iptl; |
| } |
| |
| /** |
| * @param Amalthea model ama |
| * @param Task t |
| * @return List of Tasks triggered by Task t |
| */ |
| public static List<Task> getTriggered(final Amalthea ama, final Task t) { |
| final List<Task> tl = new ArrayList<>(); |
| for (final GraphEntryBase geb : t.getCallGraph().getGraphEntries()) { |
| if (geb instanceof CallSequence) { |
| final CallSequence cs = (CallSequence) geb; |
| for (final CallSequenceItem csi : cs.getCalls()) { |
| if (csi instanceof InterProcessTrigger) { |
| final InterProcessTrigger ipt = (InterProcessTrigger) csi; |
| for (final Task tmp : ama.getSwModel().getTasks()) { |
| if (tmp.getStimuli().get(0) instanceof InterProcessStimulus) { |
| final InterProcessStimulus ips = (InterProcessStimulus) tmp.getStimuli().get(0); |
| if (ips.equals(ipt.getStimulus())) { |
| tl.add(tmp); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| return tl; |
| } |
| |
| /** |
| * Returns the first task within the given AMALTHEA model, which has the given InterProcessStimulus as a stimulus. |
| * @param amalthea model to search tasks |
| * @param ips interProcessStimulus to check |
| * @return the task, that is activated by the IPS |
| */ |
| public static Task getTrigger(final Amalthea amalthea, final InterProcessStimulus ips) { |
| for (final Task t : amalthea.getSwModel().getTasks()) { |
| for (final GraphEntryBase geb : t.getCallGraph().getGraphEntries()) { |
| if (geb instanceof CallSequence) { |
| final CallSequence cs = (CallSequence) geb; |
| for (final CallSequenceItem csi : cs.getCalls()) { |
| if (csi instanceof InterProcessTrigger) { |
| final InterProcessTrigger iptc = (InterProcessTrigger) csi; |
| if (iptc.getStimulus().getName().equals(ips.getName())) { |
| return t; |
| } |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @param model Amalthea |
| * @param ia task to processing unit mapping int array |
| * @param t Task under consideration |
| * @return long sum of WC ticks of triggered tasks by t |
| */ |
| public static long getTicksLongOfTriggeredTask(final Amalthea model, final int[] ia, final Task t) { |
| final List<InterProcessTrigger> ipts = getTriggered(t); |
| long ticks = 0; |
| /*task triggers other task*/ |
| for (final InterProcessTrigger ipt : ipts) { |
| final List<Task> triggered = model.getSwModel().getTasks().stream().filter(task -> task.getStimuli().get(0).equals(ipt.getStimulus())) |
| .collect(Collectors.toList()); |
| for (final Task task : triggered) { |
| ticks += getTicksLongForPU(CommonUtils.getPUs(model).get(ia[model.getSwModel().getTasks().indexOf(task)]), task); |
| } |
| } |
| return ticks; |
| } |
| |
| /** |
| * @param model Amalthea model |
| * @param mapping task to processing unit mapping int array |
| * @return StringBuffer containing SharedConsts class configurations |
| */ |
| public static StringBuffer appendConfig(final String model, final int[] mapping) { |
| final StringBuffer sbl = new StringBuffer(); |
| sbl.append( |
| "Configuration:\n Model,Mapping,SyncOffloading,UseModelTimeSlices,TimeSliceDerication,TimeSliceLengthInPSDefault,LevelI,TimeType,CEOnlyWrittenLabels,IgnoreInfeasibility\n"); |
| sbl.append(model + "," + Arrays.toString(mapping).replace(",", ";") + "," + SharedConsts.synchronousOffloading + "," + SharedConsts.useModelTimeSlices |
| + "," + SharedConsts.tsDeriv + "," + SharedConsts.timeSliceLengthPS + "," + SharedConsts.levelIBusyPeriod + "," + SharedConsts.timeType + "," |
| + SharedConsts.onlyWrittenLabelsCE + "," + SharedConsts.ignoreInfeasibility + "\n"); |
| return sbl; |
| } |
| |
| /** |
| * Determines whether given processing unit as index is a GPU or CPU |
| * @param pul list of PUs, of which GPUs are at the list's tail (end) |
| * @param index of the PU within given list to be chaecked |
| * @return true if pu index is a GPU |
| */ |
| public static boolean isGPUTask(final List<ProcessingUnit> pul, final int index) { |
| if (pul.get(index).getDefinition().getPuType().equals(PuType.CPU)) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @param ama Amalthea model |
| * @param t Task |
| * @param tpumap Task to PU mapping |
| * @return true, if triggered task is mapped to GPU |
| */ |
| public static boolean taskTriggersGPUTask(final Amalthea ama, final Task t, final int[] tpumap) { |
| for (final Task trigger : getTriggered(ama, t)) { |
| if (tpumap[ama.getSwModel().getTasks().indexOf(trigger)] >= getNumberofCPUs(ama)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |