blob: 0daebe2447e30152e9251228ecf52dbd2ac5b453 [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.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());
}
}
}
}