blob: 5eeb02e030b35f32d2ef4135400043d080e7bfb9 [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.algorithms;
import org.eclipse.app4mc.amalthea.model.Amalthea;
import org.eclipse.app4mc.amalthea.model.ProcessPrototype;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.multicore.partitioning.IParConstants;
import org.eclipse.app4mc.multicore.partitioning.utils.AsilToPP;
import org.eclipse.app4mc.multicore.partitioning.utils.CheckActivations;
import org.eclipse.app4mc.multicore.partitioning.utils.CheckLabels;
import org.eclipse.app4mc.multicore.partitioning.utils.CycleElimination;
import org.eclipse.app4mc.multicore.partitioning.utils.Helper;
import org.eclipse.app4mc.multicore.partitioning.utils.MergeRunnablePairings;
import org.eclipse.app4mc.multicore.partitioning.utils.RemoveGraphEdges;
import org.eclipse.app4mc.multicore.partitioning.utils.RunnableCorePairingToPP;
import org.eclipse.app4mc.multicore.partitioning.utils.TagToPP;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.preference.IPreferenceStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PrePartitioning {
private static final Logger LOGGER = LoggerFactory.getLogger(PrePartitioning.class);
private boolean activationGroups = false;
private boolean ggp = false;
private boolean efficientEdgeInCycle = false;
private boolean minimalEdgeDis = false;
private boolean tagGroups = true;
private boolean rcpGroups = false;
private boolean asilGroups = false;
private boolean rpGroups = false;
public PrePartitioning(final IPreferenceStore store) {
setActivationGroups(store.getBoolean(IParConstants.PRE_ACTIVATION));
setEfficientEdgeInCycle(store.getBoolean(IParConstants.PRE_EFF_EDGE));
setGgp(store.getBoolean(IParConstants.PRE_GGP));
setMinimalEdgeDis(store.getBoolean(IParConstants.PRE_MIN_EDGES));
setTagGroups(store.getBoolean(IParConstants.PRE_TAGS));
setRcpGroups(store.getBoolean(IParConstants.PRE_RCPC));
setAsilGroups(store.getBoolean(IParConstants.PRE_ASIL));
setRpGroups(store.getBoolean(IParConstants.PRE_RPC));
}
public PrePartitioning(final boolean ag, final boolean ggp, final boolean effEdges, final boolean minimalEdges) {
setActivationGroups(ag);
setEfficientEdgeInCycle(effEdges);
setGgp(ggp);
setMinimalEdgeDis(minimalEdges);
}
/**
* PrePartitioning performs -affinityConstraint Runnable cumulation-, -activation grouping-, -global graph grouping- and -cycle elimination- based on the
* class' parameters; the prepartitioned model will be saved along a separate file without affinitycontraints (these are replaced by cumulated runnables,
* but later on resolved into the original runnables after partitioning)
*
* @param modelCopy
* @param monitor
*/
public Amalthea performPrePartitioning(Amalthea modelCopy, final IProgressMonitor monitor) {
if (modelCopy.getSwModel() == null) {
LOGGER.error("No SW Model found. Stopping Prepartitioning");
return null;
}
/* grouping runnables into ProcessPrototypes via activation references */
if (this.activationGroups) {
genActPPs(modelCopy, monitor);
}
/* grouping runnables into ProcessPrototypes via ASIL references */
if (this.asilGroups) {
genASILPPs(modelCopy);
}
/* grouping runnables into ProcessPrototypes via tag references */
if (this.tagGroups) {
getTagPPs(modelCopy);
}
/* grouping runnables into ProcessPrototypes via RunnableCorePairing constraints */
if (this.rcpGroups) {
genRPariPPs(modelCopy);
}
/* merge Runnable pairings (affinity constraints) */
if (this.rpGroups) {
if (!modelCopy.getConstraintsModel().getAffinityConstraints().isEmpty()) {
modelCopy = new MergeRunnablePairings().merge(modelCopy);
final String str = new Helper().writePPs(modelCopy.getSwModel().getProcessPrototypes());
LOGGER.debug("RP grouping:\n{}", str);
}
else {
LOGGER.debug("No Affinity Constraints found, stopping Runnable Pairing partitioning.");
}
}
/* generating constraints model representing a graph */
genCnstrntsMdlForGraph(modelCopy, monitor);
if (aPSarepresent(modelCopy.getSwModel().getProcessPrototypes())) {
final RemoveGraphEdges rge = new RemoveGraphEdges();
rge.removeAPSRSCs(modelCopy.getConstraintsModel().getRunnableSequencingConstraints(), modelCopy.getSwModel());
modelCopy.getConstraintsModel().getRunnableSequencingConstraints().clear();
modelCopy.getConstraintsModel().getRunnableSequencingConstraints().addAll(rge.getRSCs());
}
/* perform cycle elimination / make graph acyclic */
final CycleElimination ce = new CycleElimination(modelCopy.getSwModel(), modelCopy.getConstraintsModel());
ce.setparams(this.efficientEdgeInCycle, this.minimalEdgeDis);
while (!ce.run(monitor).isOK()) {
/* wait for job to complete */
}
assert null != ce.getSwm() && null != ce.getCm();
if (ce.getSwm() == null) {
LOGGER.error("No swmodel available after CycleElimination. Stopping Prepartitioning.");
return null;
}
modelCopy.setSwModel(ce.getSwm());
modelCopy.setConstraintsModel(ce.getCm());
LOGGER.debug("Cycle elimination finished.");
/* group independent graphs into separate ProcessPrototypes */
grpIndepGraphs(modelCopy);
/* print prepartitioning result */
new Helper().writePPs(modelCopy.getSwModel().getProcessPrototypes());
LOGGER.debug("**PrePartitioning finished**");
return modelCopy;
}
private void genRPariPPs(final Amalthea modelCopy) {
if (!modelCopy.getConstraintsModel().getAffinityConstraints().isEmpty()) {
final RunnableCorePairingToPP rcp = new RunnableCorePairingToPP(modelCopy.getSwModel(), modelCopy.getConstraintsModel());
rcp.getPPsFromCorePairingsSplit();
final String str = new Helper().writePPs(modelCopy.getSwModel().getProcessPrototypes());
LOGGER.debug("RCP grouping:\n{}", str);
}
else {
LOGGER.debug("No Affinity Constraints found, stopping Runnable Core Pairing partitioning.");
}
}
private void getTagPPs(final Amalthea modelCopy) {
if (!modelCopy.getCommonElements().getTags().isEmpty()) {
final TagToPP tpp = new TagToPP(modelCopy.getSwModel(), modelCopy.getCommonElements());
tpp.createPPsFromTagsSplit();
final String str = new Helper().writePPs(modelCopy.getSwModel().getProcessPrototypes());
LOGGER.debug("Tag grouping:\n{}", str);
}
else {
LOGGER.debug("No Tags found, stopping Runnable Tag partitioning.");
}
}
private void genASILPPs(final Amalthea modelCopy) {
boolean found = false;
for (final Runnable r : modelCopy.getSwModel().getRunnables()) {
if (null != r.getAsilLevel()) {
found = true;
break;
}
}
if (found) {
final AsilToPP ac = new AsilToPP(modelCopy.getSwModel());
ac.createPPsFromASILsSplit();
final String str = new Helper().writePPs(modelCopy.getSwModel().getProcessPrototypes());
LOGGER.debug("ASIL grouping:\n{}", str);
}
else {
LOGGER.debug("No Runnable references an ASIL level. ASIL partitioning stopped.");
}
}
private void genActPPs(final Amalthea modelCopy, final IProgressMonitor monitor) {
LOGGER.debug("Starting Activations Analysis");
final CheckActivations ca = new CheckActivations();
if (modelCopy.getStimuliModel() != null) {
ca.createPPs(modelCopy.getSwModel(), modelCopy.getStimuliModel(), monitor);
}
else if (modelCopy.getStimuliModel() == null && modelCopy.getSwModel().getActivations() != null) {
ca.createPPs(modelCopy.getSwModel(), monitor);
}
else {
LOGGER.error("Neither stimulation model nor activation within swmodel found. No activation analaysis possible");
}
assert null != ca.getSwmo();
if (null == ca.getSwmo() || ca.getSwmo().getRunnables().isEmpty()) {
LOGGER.error("No Runnables at Activation Analysis.");
}
else {
modelCopy.setSwModel(ca.getSwmo());
modelCopy.setStimuliModel(ca.getStimu());
LOGGER.debug("Activation Analysis finished. Created ProcessPrototypes: {}", ca.getSwmo().getProcessPrototypes().size());
}
}
private void genCnstrntsMdlForGraph(final Amalthea modelCopy, final IProgressMonitor monitor) {
if (modelCopy.getConstraintsModel() == null || modelCopy.getConstraintsModel().getRunnableSequencingConstraints().isEmpty()) {
final CheckLabels cl = new CheckLabels();
cl.setSwm(modelCopy.getSwModel());
if (modelCopy.getConstraintsModel() != null) {
cl.setCMModel(modelCopy.getConstraintsModel());
}
cl.run(monitor);
if (cl.getCMModel() == null || cl.getCMModel().getRunnableSequencingConstraints().isEmpty()) {
LOGGER.error("No Constraintsmodel / Runnable Sequencing Constraints created! Stopping Prepartitioning.");
return;
}
if (null == modelCopy.getConstraintsModel()) {
modelCopy.setConstraintsModel(cl.getCMModel());
}
else if (modelCopy.getConstraintsModel().getRunnableSequencingConstraints().isEmpty()) {
modelCopy.getConstraintsModel().getRunnableSequencingConstraints()
.addAll(cl.getCMModel().getRunnableSequencingConstraints());
}
LOGGER.debug("Graph creation (constraint model) finished.");
}
else {
LOGGER.debug("ConstraintsModel already existing.");
}
}
private void grpIndepGraphs(final Amalthea modelCopy) {
if (this.ggp) {
LOGGER.debug("Starting to generate ProcessPrototypes for each independent graph (GGP).");
final GGP ggpl = new GGP(modelCopy.getSwModel(), modelCopy.getConstraintsModel());
ggpl.build();
assert null != ggpl.getCm() && null != ggpl.getSwm();
if (ggpl.getCm() == null) {
LOGGER.error("GGP did not result in swmodel / constraints model. Stopping Prepartitioning.");
return;
}
modelCopy.setSwModel(ggpl.getSwm());
modelCopy.setConstraintsModel(ggpl.getCm());
LOGGER.debug("GGP finished. Created ProcessPrototypes: {}", ggpl.getSwm().getProcessPrototypes().size());
}
if (new Helper().activationsAreHarmonic(modelCopy.getSwModel().getActivations())) {
LOGGER.debug(
"Activations in this model are harmonic! This allows a more sophisticated essp algorithm, that splits partitions with regard to their activation parameter!");
}
}
/**
* Checks if AccessPrecedences exist
*
* @param processPrototypes
* required since PPs may contain AccessPrecedences
* @return true if AccessPrecedences exist within PPs
*/
private boolean aPSarepresent(final EList<ProcessPrototype> processPrototypes) {
for (final ProcessPrototype pp : processPrototypes) {
if (!pp.getAccessPrecedenceSpec().isEmpty()) {
return true;
}
}
return false;
}
public void setActivationGroups(final boolean ActivationGroups) {
this.activationGroups = ActivationGroups;
}
public void setGgp(final boolean ggp) {
this.ggp = ggp;
}
public void setTagGroups(final boolean tagGroups) {
this.tagGroups = tagGroups;
}
public void setRcpGroups(final boolean rcpGroups) {
this.rcpGroups = rcpGroups;
}
public void setAsilGroups(final boolean asilGroups) {
this.asilGroups = asilGroups;
}
public void setRpGroups(final boolean rpGroups) {
this.rpGroups = rpGroups;
}
public void setMinimalEdgeDis(final boolean minimalEdgeDis) {
this.minimalEdgeDis = minimalEdgeDis;
}
public void setEfficientEdgeInCycle(final boolean effCycleElim) {
this.efficientEdgeInCycle = effCycleElim;
}
}