blob: 787cdadf50f716308439d796a52b951db2278e8e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 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.openmapping.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.app4mc.amalthea.model.ActivityGraph;
import org.eclipse.app4mc.amalthea.model.ActivityGraphItem;
import org.eclipse.app4mc.amalthea.model.CoreClassifier;
import org.eclipse.app4mc.amalthea.model.Group;
import org.eclipse.app4mc.amalthea.model.ITimeDeviation;
import org.eclipse.app4mc.amalthea.model.ModeSwitch;
import org.eclipse.app4mc.amalthea.model.PeriodicStimulus;
import org.eclipse.app4mc.amalthea.model.ProbabilitySwitch;
import org.eclipse.app4mc.amalthea.model.ReferenceObject;
import org.eclipse.app4mc.amalthea.model.RelativePeriodicStimulus;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.RunnableCall;
import org.eclipse.app4mc.amalthea.model.Stimulus;
import org.eclipse.app4mc.amalthea.model.Tag;
import org.eclipse.app4mc.amalthea.model.Task;
import org.eclipse.app4mc.amalthea.model.Time;
import org.eclipse.app4mc.amalthea.model.Value;
import org.eclipse.app4mc.multicore.sharelibs.UniversalHandler;
import org.eclipse.core.runtime.IStatus;
public class OMTask {
private static final String sTokenInclude = "[ConstraintInclude]";
private static final String sTokenExclude = "[ConstraintExclude]";
private final Task taskRef;
private OMTask predecessor = null;
private long iInstructionCount = -1;
private long iRunnableCount = -1;
private long iPeriod = -1;
/**
* Max period among all tasks, used for recursion factor calculation
*/
private static long iMaxPeriod = -1;
private ArrayList<OMAnnotationElement> validTags = new ArrayList<>();
private ArrayList<OMAnnotationElement> invalidTags = new ArrayList<>();
public OMTask(final Task taskRef) {
this.taskRef = taskRef;
addAnnotationElements();
}
public OMTask(final Task taskRef, final OMTask predecessor) {
this(taskRef);
this.predecessor = predecessor;
}
private void addAnnotationElements() {
final Map<String, Value> itPropertyConstraints;
// Check custom Properties
if (this.getTaskRef().getCustomProperties().size() > 0) {
itPropertyConstraints = this.getTaskRef().getCustomProperties().map();
itPropertyConstraints.forEach((k, v) -> parsePropertyConstraint(k, v));
}
}
// TODO This should be handled more compact
private void parsePropertyConstraint(String k, Value v) {
UniversalHandler.getInstance().logCon("T: " + taskRef.getName() + " - Parsing (K: " + k + " V: " + v + ")");
// Check if we have a valid Property Constraint
if (v instanceof ReferenceObject) {
ReferenceObject ref = (ReferenceObject) v;
if (ref.getValue() instanceof Tag) {
OMTag ot = new OMTag((Tag) ref.getValue());
if (k.contains(sTokenInclude)) {
this.validTags.add(ot);
} else if (k.contains(sTokenExclude)) {
this.invalidTags.add(ot);
} else {
// Skipping
}
}
if (ref.getValue() instanceof CoreClassifier) {
OMCoreClassifier ot = new OMCoreClassifier((CoreClassifier) ref.getValue());
if (k.contains(sTokenInclude)) {
this.validTags.add(ot);
} else if (k.contains(sTokenExclude)) {
this.invalidTags.add(ot);
} else {
// Skipping
}
}
}
}
private void fetchRunnableAndInstructionCount() {
// Check if a call graph is present in the task and if it is valid
final ActivityGraph callGraph = this.taskRef.getActivityGraph();
if (callGraph == null) {
UniversalHandler.getInstance().log("Invalid Software Model, Task '" + this.taskRef.getName()
+ "' has an invalid or missing containment to its CallGraph.", null);
return;
}
if (callGraph.getItems().isEmpty()) {
UniversalHandler.getInstance().log(
"Invalid Software Model, The CallGraph of Task '" + this.taskRef.getName() + "' is empty", null);
return;
}
// Runnable counter is increased by the child methods. Since we init it
// with -1, we have to increase it one time
// manually.
++this.iRunnableCount;
this.iInstructionCount = processCallGraph(callGraph);
}
/**
*
* @param callGraph
* @return
*/
private long processCallGraph(final ActivityGraph callGraph) {
// Count the total number of Instructions of the CallGraph
long tmpInstr = 0;
// Create iterator with call graph entries (Runnables) and process them
final Iterator<ActivityGraphItem> itGraphEntries = callGraph.getItems().iterator();
while (itGraphEntries.hasNext()) {
// Check GraphEntry Specialization and process it accordingly
final ActivityGraphItem graphEntry = itGraphEntries.next();
// CallSequence
if (graphEntry instanceof Group) {
tmpInstr += processGroup((Group) graphEntry);
}
// LabelSwitch
else if (graphEntry instanceof ModeSwitch) {
UniversalHandler.getInstance().log(
"GraphEntry specialisation LabelSwitch is not supported. Skipping...", null, IStatus.WARNING);
}
// ProbabilitySwitch
else if (graphEntry instanceof ProbabilitySwitch) {
UniversalHandler.getInstance().log(
"GraphEntry specialisation ProbabilitySwitch is not supported. Skipping...", null,
IStatus.WARNING);
}
// Unhandled, default Error
else {
UniversalHandler.getInstance().log("Unkown GraphEntry specialisation. Skipping...", null);
}
}
return tmpInstr;
}
/**
* Processes the <code>CallSequence</code> and fetches the number of
* Instructions for each of its <code>RunnableCalls</code>. Further
* handled elements may be added in the future.
*
* @param group
* The CallSequence to process
* @return Number of Instructions in the CallSequence
*/
private long processGroup(final Group group) {
// Count the total number of Instructions of the CallSequence
long tmpInstr = 0;
// Check if CallSequence is empty
if (group.getItems().isEmpty()) {
UniversalHandler.getInstance().log("Invalid Software Model, Group must not be empty. Skipping...",
null);
return tmpInstr;
}
// Process CallSequence items
final Iterator<ActivityGraphItem> itCallSeqItems = group.getItems().iterator();
while (itCallSeqItems.hasNext()) {
final ActivityGraphItem callSeqEntry = itCallSeqItems.next();
if (callSeqEntry instanceof RunnableCall) {
tmpInstr += processRunnableCall((RunnableCall) callSeqEntry);
} else {
UniversalHandler.getInstance().logWarn("Unkown CallSequenceItem specialisation. Skipping...");
}
}
return tmpInstr;
}
/**
* Processes the <code>RunnableCall</code> and fetches the number of
* Instructions for each of its <code>Runnable</code>s.
*
* @param RunnableCall
* The RunnableCall to process
* @return Number of Instructions in the RunnableCall
*/
private long processRunnableCall(final RunnableCall RunnableCall) {
final Runnable runnable = RunnableCall.getRunnable();
// Check if reference to runnable is set
if (runnable == null) {
UniversalHandler.getInstance()
.log("Invalid Software Model, reference to Runnable must not be empty. Skipping...", null);
return 0;
}
++this.iRunnableCount;
final OMRunnable r = new OMRunnable(runnable);
// TODO The Runnables should be stored in some way, maybe even the Graph
// might be build at this point
return r.getInstructionCount();
}
@Override
public String toString() {
return this.taskRef.getUniqueName();
}
/**
* Get the period period of the task activation.
*
* @param t
* @return Period of the task in pico seconds or 0 if the task has no period
*/
public long getPeriod() {
final List<Stimulus> lSt;
// Only check for the first stimulus
if ((lSt = getTaskRef().getStimuli()) == null || lSt.isEmpty()) {
UniversalHandler.getInstance().log("Stimuli not set.\nSkipping Task " + this.taskRef.getName(), null);
return iPeriod;
}
if (iPeriod < 0) {
for (Stimulus s : lSt) {
if (s instanceof PeriodicStimulus) {
PeriodicStimulus ps = (PeriodicStimulus) s;
Time x = ps.getRecurrence();
if (x == null) {
iPeriod = 0;
return iPeriod;
}
long val = x.getValue().longValue();
if (val == 0 || x.getUnit() == null) {
iPeriod = 0;
return iPeriod;
}
switch (x.getUnit()) {
case PS:
val *= 1; //
break;
case NS:
val *= 1000; //
break;
case US:
val *= 1000000L; //
break;
case MS:
val *= 1000000000L; //
break;
case S:
val *= 1000000000000L; //
break;
default:
iPeriod = 0;
return iPeriod;
}
iPeriod = val;
if (iPeriod > iMaxPeriod) {
iMaxPeriod = iPeriod;
}
return iPeriod;
}
// Support fot FMTV
if (s instanceof RelativePeriodicStimulus) {
RelativePeriodicStimulus spst = (RelativePeriodicStimulus) s;
ITimeDeviation dev = spst.getNextOccurrence();
Time x = dev.getLowerBound();
if (x == null) {
iPeriod = 0;
return iPeriod;
}
long val = x.getValue().longValue();
if (val == 0 || x.getUnit() == null) {
iPeriod = 0;
return iPeriod;
}
switch (x.getUnit()) {
case PS:
val *= 1; //
break;
case NS:
val *= 1000; //
break;
case US:
val *= 1000000L; //
break;
case MS:
val *= 1000000000L; //
break;
case S:
val *= 1000000000000L; //
break;
default:
iPeriod = 0;
return iPeriod;
}
iPeriod = val;
if (iPeriod > iMaxPeriod) {
iMaxPeriod = iPeriod;
}
return iPeriod;
}
}
iPeriod = 0;// not periodic
}
return iPeriod;
}
/**
* Returns the recursion factor of a Task
*
* The recursion factor is the quotient of the max period among all tasks
* and the period of this task, e.g. if the max period is 100ms, and this
* tasks period is 50ms, the recursion factor is 0.5.
*
* @return Double The recursion factor RF with 0.0 < RF <= 1.0
*/
public double getRecursionFactor() {
if (iPeriod < 0) {
getPeriod();
}
return iMaxPeriod / (double) iPeriod;
}
public Task getTaskRef() {
return this.taskRef;
}
public OMTask getPredecessor() {
return this.predecessor;
}
public long getInstructionCount() {
if (0 > this.iInstructionCount) {
fetchRunnableAndInstructionCount();
}
return this.iInstructionCount;
}
public long getRunnableCount() {
if (0 > this.iRunnableCount) {
fetchRunnableAndInstructionCount();
}
return this.iRunnableCount;
}
public ArrayList<OMAnnotationElement> getValidAnnotationElements() {
return this.validTags;
}
public ArrayList<OMAnnotationElement> getInvalidAnnotationElements() {
return this.invalidTags;
}
public static void init() {
iMaxPeriod = -1;
}
public static long getMaxPeriod() {
return iMaxPeriod;
}
}