| /******************************************************************************* |
| * 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.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.eclipse.app4mc.amalthea.model.ASILType; |
| import org.eclipse.app4mc.amalthea.model.Activation; |
| import org.eclipse.app4mc.amalthea.model.ActivityGraphItem; |
| import org.eclipse.app4mc.amalthea.model.AffinityConstraint; |
| import org.eclipse.app4mc.amalthea.model.Amalthea; |
| import org.eclipse.app4mc.amalthea.model.AmaltheaFactory; |
| import org.eclipse.app4mc.amalthea.model.DiscreteValueConstant; |
| import org.eclipse.app4mc.amalthea.model.Group; |
| import org.eclipse.app4mc.amalthea.model.ProcessPrototype; |
| import org.eclipse.app4mc.amalthea.model.Runnable; |
| import org.eclipse.app4mc.amalthea.model.RunnableCall; |
| import org.eclipse.app4mc.amalthea.model.RunnableEntityGroup; |
| import org.eclipse.app4mc.amalthea.model.RunnableGroup; |
| import org.eclipse.app4mc.amalthea.model.RunnablePairingConstraint; |
| import org.eclipse.app4mc.amalthea.model.Tag; |
| import org.eclipse.app4mc.amalthea.model.TagGroup; |
| import org.eclipse.app4mc.amalthea.model.Task; |
| import org.eclipse.app4mc.amalthea.model.Ticks; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class MergeRunnablePairings { |
| private static final Logger LOGGER = LoggerFactory.getLogger(MergeRunnablePairings.class); |
| |
| /** |
| * combining runnables via affinity constraints @param, @return AmaltheaModel |
| */ |
| public Amalthea merge(final Amalthea modelCopy) { |
| if (modelCopy.getConstraintsModel() != null && modelCopy.getConstraintsModel().getAffinityConstraints() != null |
| && !modelCopy.getConstraintsModel().getAffinityConstraints().isEmpty()) { |
| LOGGER.debug("Found AffinityConstraints, Creating CumulatedRunnables"); |
| final AmaltheaFactory af = AmaltheaFactory.eINSTANCE; |
| final EList<AffinityConstraint> acs = modelCopy.getConstraintsModel().getAffinityConstraints(); |
| for (final AffinityConstraint ac : acs) { |
| /* null check since runnables shall only be cumulated if they dont pair with a target (e.g. core) */ |
| if (ac instanceof RunnablePairingConstraint && ((RunnablePairingConstraint) ac).getTarget() == null) { |
| final RunnablePairingConstraint rpc = (RunnablePairingConstraint) ac; |
| ceckConsistency(rpc); |
| final Runnable r = af.createRunnable(); |
| r.setName("CumulatedRunnable" + modelCopy.getConstraintsModel().getAffinityConstraints().indexOf(ac)); |
| final RunnableGroup rg = rpc.getGroup(); |
| final RunnableEntityGroup reg = (RunnableEntityGroup) rg; |
| long instrCum = 0; |
| instrCum = addRIActTags(r, reg, instrCum); |
| final Ticks ticks = af.createTicks(); |
| final DiscreteValueConstant dvc = af.createDiscreteValueConstant(); |
| dvc.setValue(instrCum); |
| ticks.setDefault(dvc); |
| r.getActivityGraph().getItems().add(ticks); |
| modelCopy.getSwModel().getRunnables().add(r); |
| |
| /* also remove taskrunnablecall refs from tasks */ |
| rmTRCrfsFrTsks(modelCopy, reg); |
| |
| /* replace refs to cumulated runnables within processPrototypes */ |
| rplcRfsTCmltdRnnblsFPPs(modelCopy, af, r, reg); |
| new Helper().updatePPsFirstLastActParams(modelCopy.getSwModel()); |
| |
| /* remove runnable pairing runnables (cumulated runnable replaces these temporarily) */ |
| modelCopy.getSwModel().getRunnables().removeAll(reg.getRunnables()); |
| } |
| } |
| } |
| return modelCopy; |
| } |
| |
| private long addRIActTags(final Runnable r, final RunnableEntityGroup reg, long instrCum) { |
| for (final Runnable run : reg.getRunnables()) { |
| instrCum += new Helper().getInstructions(run); |
| /* do not add instruction constants / deviations; cumulation is added later */ |
| final EList<ActivityGraphItem> ril = new BasicEList<>(); |
| for (final ActivityGraphItem ri : run.getRunnableItems()) { |
| if (!(ri instanceof Ticks)) { |
| ril.add(ri); |
| } |
| } |
| r.getRunnableItems().addAll(ril); |
| r.getActivations().add(run.getFirstActivation()); |
| r.getTags().addAll(run.getTags()); |
| } |
| return instrCum; |
| } |
| |
| private void rmTRCrfsFrTsks(final Amalthea modelCopy, final RunnableEntityGroup reg) { |
| for (final Task t : modelCopy.getSwModel().getTasks()) { |
| for (final ActivityGraphItem geb : t.getActivityGraph().getItems()) { |
| if (geb instanceof Group) { |
| final EList<RunnableCall> rtrcs = new BasicEList<>(); |
| final Group cs = (Group) geb; |
| addRCsFrAGI(reg, rtrcs, cs); |
| cs.getItems().removeAll(rtrcs); |
| } |
| } |
| } |
| } |
| |
| private void addRCsFrAGI(final RunnableEntityGroup reg, final EList<RunnableCall> rtrcs, final Group cs) { |
| for (final ActivityGraphItem csi : cs.getItems()) { |
| if (csi instanceof RunnableCall) { |
| final RunnableCall trc = (RunnableCall) csi; |
| if (reg.getRunnables().contains(trc.getRunnable())) { |
| rtrcs.add(trc); |
| } |
| } |
| } |
| } |
| |
| private void rplcRfsTCmltdRnnblsFPPs(final Amalthea modelCopy, final AmaltheaFactory af, final Runnable r, |
| final RunnableEntityGroup reg) { |
| for (final ProcessPrototype pp : modelCopy.getSwModel().getProcessPrototypes()) { |
| final Iterator<RunnableCall> trcIt = pp.getRunnableCalls().iterator(); |
| final EList<RunnableCall> trcsadd = new BasicEList<>(); |
| while (trcIt.hasNext()) { |
| final RunnableCall trc = trcIt.next(); |
| if (reg.getRunnables().contains(trc.getRunnable())) { |
| trcIt.remove(); |
| if (!trcsadd.contains(trc)) { |
| final RunnableCall trcnew = af.createRunnableCall(); |
| trcnew.setRunnable(r); |
| trcsadd.add(trcnew); |
| } |
| } |
| } |
| pp.getRunnableCalls().addAll(trcsadd); |
| } |
| } |
| |
| private void ceckConsistency(final RunnablePairingConstraint rpc) { |
| if (rpc.getTarget() instanceof TagGroup) { |
| LOGGER.error("Tag Group Pairing Constraints are not yet considered during the partitioning"); |
| return; |
| } |
| final RunnableGroup rg = rpc.getGroup(); |
| final RunnableEntityGroup reg = (RunnableEntityGroup) rg; |
| |
| final Set<Activation> as = new HashSet<>(); |
| final Set<Tag> ts = new HashSet<>(); |
| final Set<ASILType> ass = new HashSet<>(); |
| |
| fillActsTagsAsils(reg, as, ts, ass); |
| final String str = "Inconsistency: RunnablePairingConstraint " + ((null != rpc.getName()) ? rpc.getName() : "") + " includes "; |
| if (as.size() > 1) { |
| final String str2 = str + as.size(); |
| LOGGER.error("{} different activations", str2); |
| } |
| if (ts.size() > 1) { |
| final String str2 = str + ts.size(); |
| LOGGER.error("{} different tags", str2); |
| } |
| if (ass.size() > 1) { |
| final String str2 = str + as.size(); |
| LOGGER.error("{} different ASIL-levels", str2); |
| } |
| |
| /* final output */ |
| if (as.size() > 1 || ts.size() > 1 || ass.size() > 1) { |
| LOGGER.debug( |
| "This inconsistency results in tasks with mixed-up references. To resolve this, please carefully check your ASIL, Tag, and Activation references for the pairing constraint {}", |
| ((null != rpc.getName()) ? rpc.getName() : "")); |
| } |
| } |
| |
| private void fillActsTagsAsils(final RunnableEntityGroup reg, final Set<Activation> as, final Set<Tag> ts, final Set<ASILType> ass) { |
| for (final Runnable r : reg.getRunnables()) { |
| /* check activations */ |
| if (!as.contains(r.getFirstActivation())) { |
| as.add(r.getFirstActivation()); |
| } |
| /* check tags */ |
| for (final Tag tag : r.getTags()) { |
| if (!ts.contains(tag)) { |
| ts.addAll(r.getTags()); |
| } |
| } |
| /* check asil levels */ |
| if (!ass.contains(r.getAsilLevel())) { |
| ass.add(r.getAsilLevel()); |
| } |
| } |
| } |
| } |