blob: 812f3b7ba562c2b3ae450b9904f7171531efebeb [file] [log] [blame]
/*******************************************************************************
* 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;
}
}