/******************************************************************************* | |
* Copyright (c) 2017-2020 Dortmund University of Applied Sciences and Arts and others. | |
* | |
* This program and the accompanying materials are made | |
* available under the terms of the Eclipse Public License 2.0 | |
* which is available at https://www.eclipse.org/legal/epl-2.0/ | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* Dortmund University of Applied Sciences and Arts - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.app4mc.multicore.partitioning.utils; | |
import java.math.BigInteger; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map.Entry; | |
import java.util.Set; | |
import java.util.stream.Collectors; | |
import org.eclipse.app4mc.amalthea.model.AccessPrecedenceSpec; | |
import org.eclipse.app4mc.amalthea.model.Activation; | |
import org.eclipse.app4mc.amalthea.model.ActivityGraphItem; | |
import org.eclipse.app4mc.amalthea.model.Amalthea; | |
import org.eclipse.app4mc.amalthea.model.AmaltheaFactory; | |
import org.eclipse.app4mc.amalthea.model.ConstraintsModel; | |
import org.eclipse.app4mc.amalthea.model.ExecutionNeed; | |
import org.eclipse.app4mc.amalthea.model.IDiscreteValueDeviation; | |
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.PeriodicActivation; | |
import org.eclipse.app4mc.amalthea.model.ProcessPrototype; | |
import org.eclipse.app4mc.amalthea.model.ProcessingUnitDefinition; | |
import org.eclipse.app4mc.amalthea.model.Runnable; | |
import org.eclipse.app4mc.amalthea.model.RunnableCall; | |
import org.eclipse.app4mc.amalthea.model.RunnableSequencingConstraint; | |
import org.eclipse.app4mc.amalthea.model.SWModel; | |
import org.eclipse.app4mc.amalthea.model.Task; | |
import org.eclipse.app4mc.amalthea.model.Ticks; | |
import org.eclipse.app4mc.amalthea.model.util.CustomPropertyUtil; | |
import org.eclipse.app4mc.amalthea.model.util.SoftwareUtil; | |
import org.eclipse.app4mc.multicore.partitioning.algorithms.Path; | |
import org.eclipse.app4mc.multicore.sharelibs.UniversalHandler; | |
import org.eclipse.core.runtime.NullProgressMonitor; | |
import org.eclipse.emf.common.util.BasicEList; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.URI; | |
import org.jgrapht.DirectedGraph; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* Provides several calculations / generally needed methods | |
*/ | |
public class Helper { | |
private static final Logger LOGGER = LoggerFactory.getLogger(Helper.class); | |
private static final String KEY = "slack"; | |
/** | |
* Calculation of a runnable's instructions (arithmetic average in case of deviations) | |
* | |
* @param r | |
* Runnable | |
* @return long mean instructions | |
*/ | |
public long getInstructions(final Runnable r) { | |
if (null == r) { | |
return 0l; | |
} | |
long instr = 0; | |
if (null != SoftwareUtil.getExecutionNeeds(r, null)) { | |
for (final ExecutionNeed en : SoftwareUtil.getExecutionNeeds(r, null)) { | |
for (final Entry<String, IDiscreteValueDeviation> n : en.getNeeds()) { | |
instr += n.getValue().getUpperBound(); | |
} | |
} | |
} | |
if (null != SoftwareUtil.getTicks(r, null)) { | |
for (final Ticks ticks : SoftwareUtil.getTicks(r, null)) { | |
instr += getDefaultOrExtendedTicks(ticks); | |
} | |
} | |
return instr == 0 ? 1 : instr; | |
} | |
public long getInstructions(final EList<Runnable> rs) { | |
long instr = 0; | |
for (final Runnable r : rs) { | |
instr += getInstructions(r); | |
} | |
return instr; | |
} | |
List<Runnable> visited = new BasicEList<>(); | |
/** | |
* Get ProcessPrototype from a Runnable (the ProcessPrototype, that contains | |
* the given runnable) | |
* | |
* @param runnable | |
* @param swm | |
* @return ProcessPrototype, that contains the parameter runnable | |
*/ | |
public ProcessPrototype getPPfromR(final Runnable runnable, final SWModel swm) { | |
for (final ProcessPrototype pp : swm.getProcessPrototypes()) { | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
if (trc.getRunnable().equals(runnable)) { | |
return pp; | |
} | |
} | |
} | |
LOGGER.error("getPPFromR did not find PP for Runnable {}", runnable.getName()); | |
return null; | |
} | |
/** | |
* calculates the longest runtime of a runnable according to all succeeding (dependent) runnables recursively. Function is able to handle cyclic graphs. | |
* | |
* @param cm | |
* constraints model represents dependencies | |
* @param r | |
* the given runnable thats runtime shall be calculated | |
* @return runtime of succeeding runnables and the runnable's runtime | |
*/ | |
public long getPreceedingRunTimeCycle(final ConstraintsModel cm, final Runnable r) { | |
if (r == null) { | |
return Long.MAX_VALUE; | |
} | |
long rt = 0; | |
this.visited.add(r); | |
for (final RunnableSequencingConstraint rsc : cm.getRunnableSequencingConstraints()) { | |
if (rsc.getRunnableGroups().get(1).getRunnables().get(0).equals(r) | |
&& !this.visited.contains(rsc.getRunnableGroups().get(0).getRunnables().get(0))) { | |
final long temp = getPreceedingRunTimeCycle(cm, rsc.getRunnableGroups().get(0).getRunnables().get(0)); | |
if (temp > rt) { | |
rt = temp; | |
} | |
} | |
} | |
return rt + getInstructions(r); | |
} | |
private final HashMap<Runnable, Set<Runnable>> cache = new HashMap<>(); | |
/** | |
* | |
* @param cm | |
* constraints model represents dependencies | |
* @param r | |
* runnable of which predecessors should be found | |
* @return predecessors of r | |
*/ | |
public Set<Runnable> getPreceedingRunnables(final ConstraintsModel cm, final Runnable r, | |
final DirectedGraph<Runnable, RunnableSequencingConstraint> directedGraph) { | |
if (this.cache.containsKey(r)) { | |
return this.cache.get(r); | |
} | |
final Set<Runnable> rs = new HashSet<>(); | |
/* it is more efficient if directedGraph is used */ | |
if (null == directedGraph) { | |
for (final RunnableSequencingConstraint rsc : cm.getRunnableSequencingConstraints()) { | |
if (rsc.getRunnableGroups().get(1).getRunnables().get(0).equals(r)) { | |
rs.add(rsc.getRunnableGroups().get(0).getRunnables().get(0)); | |
rs.addAll(getPreceedingRunnables(cm, rsc.getRunnableGroups().get(0).getRunnables().get(0), directedGraph)); | |
} | |
} | |
} | |
else { | |
for (final RunnableSequencingConstraint rsc : directedGraph.incomingEdgesOf(r)) { | |
rs.add(rsc.getRunnableGroups().get(0).getRunnables().get(0)); | |
rs.addAll(getPreceedingRunnables(cm, rsc.getRunnableGroups().get(0).getRunnables().get(0), directedGraph)); | |
} | |
} | |
this.cache.put(r, rs); | |
return rs; | |
} | |
/** | |
* creates a ProcessPrototype with all runnables | |
* | |
* @param swm | |
*/ | |
public void checkTRCsVsAllRunnables(final SWModel swm) { | |
if (getAllTRCs(swm).size() < swm.getRunnables().size()) { | |
final ProcessPrototype pp = AmaltheaFactory.eINSTANCE.createProcessPrototype(); | |
pp.setName("AllRunnables"); | |
final EList<RunnableCall> alltrcs = new BasicEList<>(); | |
for (final Runnable r : swm.getRunnables()) { | |
final RunnableCall trc = AmaltheaFactory.eINSTANCE.createRunnableCall(); | |
trc.setRunnable(r); | |
alltrcs.add(trc); | |
} | |
pp.getRunnableCalls().addAll(alltrcs); | |
swm.getProcessPrototypes().add(pp); | |
LOGGER.debug("Created AllRunnablesPP with {} TRCs", alltrcs.size()); | |
} | |
} | |
/** | |
* Checks if all runnables within the given software model reference an activation | |
* | |
* @param swm | |
* | |
* @return false if any runnable has no activation reference, true otherwise | |
*/ | |
public boolean allRunnablesReferActivation(final SWModel swm) { | |
for (final Runnable r : swm.getRunnables()) { | |
if (null == r.getFirstActivation()) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* | |
* @return all runnablecalls across processprototypes | |
*/ | |
public EList<RunnableCall> getAllTRCs(final SWModel swm) { | |
final EList<RunnableCall> trcs = new BasicEList<>(); | |
for (final ProcessPrototype pp : swm.getProcessPrototypes()) { | |
trcs.addAll(pp.getRunnableCalls()); | |
} | |
return trcs; | |
} | |
/** | |
* calculates the longest runtime of a runnable according to all succeeding (dependent) runnables recursivly. Function is able to handle cyclic graphs | |
* | |
* @param cm | |
* constraints model represents dependencies | |
* @param r | |
* the given runnable thats runtime shall be calculated | |
* @return runtime of succeeding runnables and the runnable's runtime | |
*/ | |
public long getSucceedingRunTimeCycle(final ConstraintsModel cm, final Runnable r) { | |
if (r == null) { | |
return Long.MAX_VALUE; | |
} | |
long rt = 0; | |
this.visited.add(r); | |
for (final RunnableSequencingConstraint rsc : cm.getRunnableSequencingConstraints()) { | |
if (rsc.getRunnableGroups().get(0).getRunnables().get(0).equals(r) | |
&& !this.visited.contains(rsc.getRunnableGroups().get(1).getRunnables().get(0))) { | |
final long temp = getSucceedingRunTimeCycle(cm, rsc.getRunnableGroups().get(1).getRunnables().get(0)); | |
if (temp > rt) { | |
rt = temp; | |
} | |
} | |
} | |
return rt + getInstructions(r); | |
} | |
/** | |
* determination of a common label that two runnables access | |
* | |
* @param runnable | |
* @param runnable2 | |
* @return label common | |
*/ | |
public Label getCommonLabel(final Runnable runnable, final Runnable runnable2) { | |
for (final ActivityGraphItem ri1 : runnable.getRunnableItems()) { | |
if (ri1 instanceof LabelAccess) { | |
final LabelAccess la1 = (LabelAccess) ri1; | |
for (final ActivityGraphItem ri2 : runnable2.getRunnableItems()) { | |
if (ri2 instanceof LabelAccess) { | |
return extracted(la1, ri2); | |
} | |
} | |
} | |
} | |
return null; | |
} | |
private Label extracted(final LabelAccess la1, final ActivityGraphItem ri2) { | |
final LabelAccess la2 = (LabelAccess) ri2; | |
if (la1.getData().equals(la2.getData()) && ((la1.getAccess().equals(LabelAccessEnum.READ) && la2.getAccess().equals(LabelAccessEnum.WRITE)) | |
|| (la1.getAccess().equals(LabelAccessEnum.WRITE) && la2.getAccess().equals(LabelAccessEnum.READ)))) { | |
return la1.getData(); | |
} | |
return null; | |
} | |
/** | |
* calls UniversalHandler() and writes the @param models into the original file, thats filename is extended by @param name | |
* | |
* @param event | |
* ExecutionEvent for File information | |
*/ | |
public static void writeModelFile(final URI path, final Amalthea ama) { | |
LOGGER.debug("Writing {}\n", path); | |
UniversalHandler.getInstance().writeModel(path, ama); | |
} | |
/** | |
* Get all runnables from a ProcessPrototype in form of an EList | |
* | |
* @param pp | |
* @return Elist<Runnable> all runnables contained in pp | |
*/ | |
public EList<Runnable> getRunnables(final ProcessPrototype pp) { | |
final EList<Runnable> rl = new BasicEList<>(); | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
rl.add(trc.getRunnable()); | |
} | |
return rl; | |
} | |
/** | |
* Set all model received from @param UniversalHandler to @return & @param Amalthea model | |
*/ | |
public Amalthea setAllModels(final Amalthea amodels, final UniversalHandler uh) { | |
amodels.setCommonElements(uh.getCommonElements()); | |
amodels.setConstraintsModel(uh.getConstraintsModel()); | |
amodels.setHwModel(uh.getHwModel()); | |
amodels.setMappingModel(uh.getMappingModel()); | |
amodels.setOsModel(uh.getOsModel()); | |
amodels.setPropertyConstraintsModel(uh.getPropertyConstraintsModel()); | |
amodels.setStimuliModel(uh.getStimuliModel()); | |
amodels.setSwModel(uh.getSwModel()); | |
amodels.setEventModel(uh.getEvModel()); | |
amodels.setComponentsModel(uh.getComModel()); | |
amodels.setConfigModel(uh.getConfModel()); | |
return amodels; | |
} | |
public void assignAPs(final Set<AccessPrecedenceSpec> aps) { | |
for (final AccessPrecedenceSpec ap : aps) { | |
final Runnable r = ap.getOrigin(); | |
final EList<RunnableCall> trcs = r.getRunnableCalls(); | |
for (final RunnableCall trc : trcs) { | |
ProcessPrototype pp = AmaltheaFactory.eINSTANCE.createProcessPrototype(); | |
if (trc.eContainer() instanceof ProcessPrototype) { | |
pp = (ProcessPrototype) trc.eContainer(); | |
} | |
if (null != pp.getName() && !pp.getAccessPrecedenceSpec().contains(ap)) { | |
pp.getAccessPrecedenceSpec().add(ap); | |
} | |
} | |
} | |
} | |
/** | |
* Updates ProcessScope wrt ProcessPrototypes of all RSCs | |
* | |
* @param amodels | |
* @return | |
*/ | |
public ConstraintsModel updateRSCs(final ConstraintsModel cm, final SWModel swm) { | |
for (final RunnableSequencingConstraint rsc : cm.getRunnableSequencingConstraints()) { | |
final Runnable source = rsc.getRunnableGroups().get(0).getRunnables().get(0); | |
final Runnable target = rsc.getRunnableGroups().get(1).getRunnables().get(0); | |
for (final ProcessPrototype pp : swm.getProcessPrototypes()) { | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
if (trc.getRunnable().equals(source) || trc.getRunnable().equals(target)) { | |
rsc.getProcessScope().clear(); | |
rsc.getProcessScope().add(pp); | |
} | |
} | |
} | |
} | |
return cm; | |
} | |
/** | |
* Adds ProcessPrototypes' FirstRunnable, LastRunnable, and Activation properties | |
* | |
* @param swm | |
* @return | |
*/ | |
public SWModel updatePPsFirstLastActParams(final SWModel swm) { | |
for (final ProcessPrototype pp : swm.getProcessPrototypes()) { | |
setFirstLastRunnable(pp); | |
if (null == pp.getActivation() && !pp.getRunnableCalls().isEmpty() && pp.getRunnableCalls().get(0).getRunnable().getFirstActivation() != null) { | |
pp.setActivation(pp.getRunnableCalls().get(0).getRunnable().getFirstActivation()); | |
} | |
else if (!pp.getRunnableCalls().isEmpty() && pp.getRunnableCalls().get(0).getRunnable().getFirstActivation() == null) { | |
LOGGER.debug("Runnable {} has no activation, this might be a problem for the mapping process.", | |
pp.getRunnableCalls().get(0).getRunnable().getName()); | |
} | |
} | |
return swm; | |
} | |
private void setFirstLastRunnable(final ProcessPrototype pp) { | |
if (!pp.getRunnableCalls().isEmpty()) { | |
if (pp.getFirstRunnable() == null || pp.getFirstRunnable() != pp.getRunnableCalls().get(0).getRunnable()) { | |
pp.setFirstRunnable(pp.getRunnableCalls().get(0).getRunnable()); | |
} | |
if (pp.getLastRunnable() == null || pp.getLastRunnable() != pp.getRunnableCalls().get(pp.getRunnableCalls().size() - 1).getRunnable()) { | |
pp.setLastRunnable(pp.getRunnableCalls().get(pp.getRunnableCalls().size() - 1).getRunnable()); | |
} | |
} | |
} | |
private static final String LINE = "******************************************************\n"; | |
/** | |
* | |
* @param processPrototypes | |
* @return String with PP.name(sum(instructions)):Runnable1 Runnable2 ... | |
*/ | |
public String writePPs(final EList<ProcessPrototype> processPrototypes) { | |
final StringBuilder sb = new StringBuilder(); | |
short i = 0; | |
sb.append(Helper.LINE); | |
sb.append(String.format("%2S%22S%16S%6S", " #", "PP", "Instructionssum", "#TRCs") + " TRCs\n"); | |
sb.append(Helper.LINE); | |
for (final ProcessPrototype pp : processPrototypes) { | |
long ppt = 0; | |
final int slack = null != CustomPropertyUtil.customGetInteger(pp, KEY) ? CustomPropertyUtil.customGetInteger(pp, KEY) : 0; | |
sb.append(String.format("%2s%22.21s%16.15s%6s", i++, pp.getName(), getPPInstructions(pp), pp.getRunnableCalls().size()) + " "); | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
final long inc = new Helper().getInstructions(trc.getRunnable()); | |
final int cslack = null != CustomPropertyUtil.customGetInteger(trc, KEY) ? CustomPropertyUtil.customGetInteger(trc, KEY) : 0; | |
/*name (start, end, predsRT)*/ | |
sb.append(String.format("%43.43s", | |
String.format("%20.20s", trc.getRunnable().getName()) + "(" + (ppt + cslack) + "," + (ppt + cslack + inc) + ")")); | |
ppt += inc + cslack; | |
} | |
if (slack > 0) { | |
sb.append(" !! slack cumulated: " + slack); | |
} | |
sb.append("\n"); | |
} | |
sb.append(Helper.LINE); | |
return sb.toString(); | |
} | |
public String writeTasks(final EList<Task> tasks) { | |
final StringBuilder sb = new StringBuilder(); | |
short i = 0; | |
sb.append(Helper.LINE); | |
sb.append(String.format("%2S%22S%16S%6S", " #", "PP", "Instructionssum", "#TRCs") + " TRCs\n"); | |
sb.append(Helper.LINE); | |
for (final Task task : tasks) { | |
long ppt = 0; | |
final int slack = null != CustomPropertyUtil.customGetInteger(task, KEY) ? CustomPropertyUtil.customGetInteger(task, KEY) : 0; | |
sb.append(String.format("%2s%22.21s%16.15s%6s", i++, task.getName(), getTaskInstructions(task), task.getActivityGraph().getItems().size()) + " "); | |
final List<RunnableCall> rl = task.getActivityGraph().getItems().stream().filter(agi -> agi instanceof RunnableCall).map(agi -> (RunnableCall) agi) | |
.collect(Collectors.toList()); | |
for (final RunnableCall trc : rl) { | |
final long inc = new Helper().getInstructions(trc.getRunnable()); | |
final int cslack = null != CustomPropertyUtil.customGetInteger(trc, KEY) ? CustomPropertyUtil.customGetInteger(trc, KEY) : 0; | |
/*name (start, end, predsRT)*/ | |
sb.append(String.format("%43.43s", | |
String.format("%20.20s", trc.getRunnable().getName()) + "(" + (ppt + cslack) + "," + (ppt + cslack + inc) + ")")); | |
ppt += inc + cslack; | |
} | |
if (slack > 0) { | |
sb.append(" !! slack cumulated: " + slack); | |
} | |
sb.append("\n"); | |
} | |
sb.append(Helper.LINE); | |
return sb.toString(); | |
} | |
private long getTaskInstructions(final Task task) { | |
long instrSum = 0; | |
for (final ActivityGraphItem agi : task.getActivityGraph().getItems()) { | |
if (agi instanceof RunnableCall) { | |
final RunnableCall rc = (RunnableCall) agi; | |
instrSum += getInstructions(rc.getRunnable()); | |
final int slack = null != CustomPropertyUtil.customGetInteger(rc, KEY) ? CustomPropertyUtil.customGetInteger(rc, KEY) : 0; | |
instrSum += slack > 0 ? slack : 0; | |
} | |
} | |
return instrSum; | |
} | |
/** | |
* | |
* @param pp | |
* @return long the sum of the PP's Runnable Instructions | |
*/ | |
public long getPPInstructions(final ProcessPrototype pp) { | |
long instrSum = 0; | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
instrSum += getInstructions(trc.getRunnable()); | |
final int slack = null != CustomPropertyUtil.customGetInteger(trc, KEY) ? CustomPropertyUtil.customGetInteger(trc, KEY) : 0; | |
instrSum += slack > 0 ? slack : 0; | |
} | |
return instrSum; | |
} | |
/** | |
* @param pp | |
* @return double sum of all runnbles' instructions multiplied with PP's periodic activation in seconds | |
*/ | |
public double getPPIntrSumActRel(final ProcessPrototype pp) { | |
long instrSum = 0; | |
for (final RunnableCall trc : pp.getRunnableCalls()) { | |
instrSum += getInstructions(trc.getRunnable()); | |
} | |
/* mpis = multiplier in seconds */ | |
double mpis = 1; | |
if (pp.getActivation() instanceof PeriodicActivation) { | |
final PeriodicActivation pact = (PeriodicActivation) pp.getActivation(); | |
/*e.g. 250ms => *4 (=(1/0.001)/250)*/ | |
mpis = (1 / getTimeUnit(pact)) / getMeanActivation(pact); | |
} | |
instrSum *= mpis; | |
return instrSum; | |
} | |
private double getMeanActivation(final PeriodicActivation pact) { | |
if (null != pact.getMax() && null != pact.getMin() && null != pact.getMax().getValue() && null != pact.getMin().getValue() | |
&& null != pact.getMax().getUnit() && null != pact.getMin().getUnit()) { | |
return (pact.getMax().getValue().add(pact.getMin().getValue())).divide(BigInteger.valueOf(2)).doubleValue(); | |
} | |
LOGGER.error("{} min/max values set", pact.getName()); | |
return 1; | |
} | |
/** | |
* @param pact | |
* @return double fraction representing the time unit of the given period | |
*/ | |
public double getTimeUnit(final Activation pact) { | |
if (pact instanceof PeriodicActivation) { | |
final PeriodicActivation periodic = (PeriodicActivation) pact; | |
if (null != periodic.getMax() && null != periodic.getMax().getUnit()) { | |
switch (periodic.getMax().getUnit()) { | |
case MS: | |
return 0.001; | |
case US: | |
return 0.000001; | |
case NS: | |
return 0.000000001; | |
case PS: | |
return 0.000000000001; | |
case S: | |
return 1; | |
default: | |
break; | |
} | |
} | |
else { | |
LOGGER.error("{} requres a max value and a timeunit to be set", periodic.getName()); | |
} | |
} | |
return 0; | |
} | |
/** | |
* @param rscl | |
* @return true if all RunnableSequencingConstraints have two groups and at least one runnable in each | |
*/ | |
public boolean allRSCsHave2ValidEntries(final EList<RunnableSequencingConstraint> rscl) { | |
for (final RunnableSequencingConstraint rsc : rscl) { | |
if (null == rsc.getRunnableGroups().get(0) || null == rsc.getRunnableGroups().get(1) || rsc.getRunnableGroups().get(0).getRunnables().isEmpty() | |
|| rsc.getRunnableGroups().get(1).getRunnables().isEmpty()) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* @param swm | |
* @return true if all Runnables are called once (single task runnable call) | |
*/ | |
public boolean tRCsAreConsist(final SWModel swm) { | |
for (final Runnable r : swm.getRunnables()) { | |
if (r.getRunnableCalls().size() > 1) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* checks whether all periodic activations are harmonic | |
* | |
* @return true if periodic activations are harmonic | |
*/ | |
public boolean activationsAreHarmonic(final EList<Activation> acts) { | |
final ArrayList<Double> pacts = new ArrayList<>(); | |
for (final Activation act : acts) { | |
if (act instanceof PeriodicActivation) { | |
final PeriodicActivation pa = (PeriodicActivation) act; | |
pacts.add(getMeanActivation(pa)); | |
} | |
else { | |
LOGGER.debug("{} is not a periodic activation and is ignored for harmonic activation analysis.", act.getName()); | |
} | |
} | |
Collections.sort(pacts, Collections.reverseOrder()); | |
if (pacts.size() > 1) { | |
for (int i = 0; i < pacts.size(); i++) { | |
final Double currentAct = pacts.get(i); | |
for (int j = i; j < pacts.size(); j++) { | |
if (currentAct % pacts.get(j) > 0) { | |
return false; | |
} | |
} | |
} | |
} | |
return true; | |
} | |
public boolean runnablesContainedinSamePP(final EList<Runnable> runnables, final EList<Runnable> runnables2) { | |
for (final Runnable r : runnables) { | |
for (final Runnable r2 : runnables2) { | |
for (final RunnableCall rc : r.getRunnableCalls()) { | |
for (final RunnableCall rc2 : r2.getRunnableCalls()) { | |
if (rc.eContainer().equals(rc2.eContainer())) { | |
return true; | |
} | |
} | |
} | |
} | |
} | |
return false; | |
} | |
public boolean runnablesContainedinSamePP(final Runnable r1, final Runnable r2) { | |
for (final RunnableCall trc1 : r1.getRunnableCalls()) { | |
for (final RunnableCall trc2 : r2.getRunnableCalls()) { | |
if (trc1.eContainer().equals(trc2.eContainer())) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
public long getDefaultOrExtendedTicks(final Ticks ticks) { | |
long ret = 0l; | |
if (null != ticks.getDefault() && ticks.getDefault().getUpperBound() > 0) { | |
return ticks.getDefault().getUpperBound(); | |
} | |
if (null != ticks.getExtended()) { | |
long max = 0; | |
for (final Entry<ProcessingUnitDefinition, IDiscreteValueDeviation> ticksl : ticks.getExtended()) { | |
if (ticksl.getValue().getUpperBound() > max) { | |
max = ticksl.getValue().getUpperBound(); | |
} | |
} | |
ret = max; | |
} | |
return ret; | |
} | |
public long getDefaultOrExtendedTicks(final List<Ticks> ticks) { | |
long ret = 0; | |
for (final Ticks ticksl : ticks) { | |
ret += getDefaultOrExtendedTicks(ticksl); | |
} | |
return ret; | |
} | |
public ConstraintsModel ensureDepsNoCycles(final Amalthea ama) { | |
/* If no dependencies (runnable sequencing constraints) exist, | |
* (i) analyze runnable label accesses and create RSCs | |
* (ii) decompose cycles */ | |
ConstraintsModel cm = ama.getConstraintsModel(); | |
if (null == cm || cm.getRunnableSequencingConstraints().isEmpty()) { | |
final CheckLabels cl = new CheckLabels(); | |
cl.setSwm(ama.getSwModel()); | |
cl.setCMModel(cm); | |
cl.run(new NullProgressMonitor()); | |
cm = cl.getCMModel(); | |
} | |
final CycleElimination ce = new CycleElimination(ama.getSwModel(), cm); | |
if (ce.containsCycles()) { | |
ce.run(new NullProgressMonitor()); | |
cm = ce.getCm(); | |
} | |
ama.setConstraintsModel(cm); | |
return cm; | |
} | |
public long getRSLenth(final Path cpt) { | |
long sum = 0; | |
for (final Runnable r : cpt.getRunnables()) { | |
sum += getInstructions(r); | |
} | |
return sum; | |
} | |
} |