| /******************************************************************************* |
| * 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; |
| } |
| } |