blob: c3c96942eea9f3de2d561fa2be45daa3640f0c36 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2021 Robert Bosch GmbH 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:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.model.util;
import static org.eclipse.app4mc.amalthea.model.LabelAccessEnum.READ;
import static org.eclipse.app4mc.amalthea.model.LabelAccessEnum.WRITE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.app4mc.amalthea.model.ActivityGraphItem;
import org.eclipse.app4mc.amalthea.model.AmaltheaServices;
import org.eclipse.app4mc.amalthea.model.ClearEvent;
import org.eclipse.app4mc.amalthea.model.Condition;
import org.eclipse.app4mc.amalthea.model.ConditionConjunction;
import org.eclipse.app4mc.amalthea.model.ConditionDisjunction;
import org.eclipse.app4mc.amalthea.model.ConditionDisjunctionEntry;
import org.eclipse.app4mc.amalthea.model.EnumMode;
import org.eclipse.app4mc.amalthea.model.ExecutionNeed;
import org.eclipse.app4mc.amalthea.model.Group;
import org.eclipse.app4mc.amalthea.model.IActivityGraphItemContainer;
import org.eclipse.app4mc.amalthea.model.IExecutable;
import org.eclipse.app4mc.amalthea.model.Label;
import org.eclipse.app4mc.amalthea.model.LabelAccess;
import org.eclipse.app4mc.amalthea.model.LabelAccessEnum;
import org.eclipse.app4mc.amalthea.model.LabelAccessStatistic;
import org.eclipse.app4mc.amalthea.model.MinAvgMaxStatistic;
import org.eclipse.app4mc.amalthea.model.ModeLabel;
import org.eclipse.app4mc.amalthea.model.ModeLabelCondition;
import org.eclipse.app4mc.amalthea.model.ModeLiteral;
import org.eclipse.app4mc.amalthea.model.ModeSwitch;
import org.eclipse.app4mc.amalthea.model.ModeSwitchEntry;
import org.eclipse.app4mc.amalthea.model.ModeValueCondition;
import org.eclipse.app4mc.amalthea.model.NumericMode;
import org.eclipse.app4mc.amalthea.model.NumericStatistic;
import org.eclipse.app4mc.amalthea.model.ProbabilitySwitch;
import org.eclipse.app4mc.amalthea.model.ProbabilitySwitchEntry;
import org.eclipse.app4mc.amalthea.model.Process;
import org.eclipse.app4mc.amalthea.model.RelationalOperator;
import org.eclipse.app4mc.amalthea.model.Runnable;
import org.eclipse.app4mc.amalthea.model.RunnableCall;
import org.eclipse.app4mc.amalthea.model.ServerCall;
import org.eclipse.app4mc.amalthea.model.SetEvent;
import org.eclipse.app4mc.amalthea.model.SingleValueStatistic;
import org.eclipse.app4mc.amalthea.model.Switch;
import org.eclipse.app4mc.amalthea.model.SwitchEntry;
import org.eclipse.app4mc.amalthea.model.Ticks;
import org.eclipse.app4mc.amalthea.model.WaitEvent;
import org.eclipse.app4mc.amalthea.model.WhileLoop;
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.jdt.annotation.NonNull;
import com.google.common.primitives.Ints;
public class SoftwareUtil {
// Suppress default constructor
private SoftwareUtil() {
throw new IllegalStateException("Utility class");
}
/**
* Traverse the contained call graph items and collect all items.
*
* @param container call graph, group, ...
* @return
* List of ActivityGraphItems
*/
public static EList<ActivityGraphItem> collectActivityGraphItems(final IActivityGraphItemContainer container) {
return collectActivityGraphItems(container, null, ActivityGraphItem.class, null);
}
/**
* Traverse the contained call graph items and collect all items.
* Collection can be restricted to specific modes.
*
* @param container call graph, group, ...
* @param modes (optional) - null works
* @return
* List of ActivityGraphItems
*/
public static EList<ActivityGraphItem> collectActivityGraphItems(final IActivityGraphItemContainer container, final EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(container, modes, ActivityGraphItem.class, null);
}
/**
* Traverse the contained call graph items and collect all items.
* Collection can be restricted to specific modes and filtered by a lambda expression.
*
* @param container call graph, group, ...
* @param modes (optional) - null works
* @param filter lambda expression (e.g. "a -&gt; a instanceof LabelAccess")
* @return
* List of ActivityGraphItems
*/
public static EList<ActivityGraphItem> collectActivityGraphItems(final IActivityGraphItemContainer container, final EMap<ModeLabel, String> modes,
final Function<ActivityGraphItem, Boolean> filter) {
return collectActivityGraphItems(container, modes, ActivityGraphItem.class, filter);
}
/**
* Traverse the runnable items graph of a runnable and collect all items.
* Collection can be restricted to specific modes and filtered by class.
*
* @param container call graph, group, ...
* @param modes (optional) - null works
* @param targetClass subclass of ActivityGraphItem that restricts the result
* @return
* List of T extends ActivityGraphItems
*/
public static <T extends ActivityGraphItem> EList<T> collectActivityGraphItems(final IActivityGraphItemContainer container, final EMap<ModeLabel, String> modes,
final Class<T> targetClass) {
return collectActivityGraphItems(container, modes, targetClass, null);
}
/**
* Traverse the runnable items graph of a runnable and collect all items.
* Collection can be restricted to specific modes and filtered by class and lambda expression.
*
* @param container call graph, group, ...
* @param modes (optional) - null works
* @param targetClass subclass of ActivityGraphItem that restricts the result
* @param filter lambda expression (e.g. "a -&gt; a instanceof LabelAccess")
* @return
* List of T extends ActivityGraphItems
*/
public static <T extends ActivityGraphItem> EList<T> collectActivityGraphItems(final IActivityGraphItemContainer container, final EMap<ModeLabel, String> modes,
final Class<T> targetClass, final Function<T, Boolean> filter) {
EList<T> itemList = new BasicEList<>();
if (container != null) {
collectActivityGraphItems(container.getItems(), modes, targetClass, filter, itemList);
}
return itemList;
}
private static <T extends ActivityGraphItem> void collectActivityGraphItems(final EList<ActivityGraphItem> input, final EMap<ModeLabel, String> modes,
final Class<T> targetClass, final Function<T, Boolean> filter, final List<T> itemList) {
for (ActivityGraphItem item : input) {
if (item instanceof Group) {
// **** Group
collectActivityGraphItems(((Group) item).getItems(), modes, targetClass, filter, itemList);
} else if (item instanceof WhileLoop) {
// **** WhileLoop
collectWhileLoopItems((WhileLoop) item, modes, targetClass, filter, itemList);
} else if (item instanceof Switch) {
// **** Switch -> check conditions
collectSwitchItems((Switch) item, modes, targetClass, filter, itemList);
} else if (item instanceof ModeSwitch) {
// **** ModeSwitch -> check conditions
collectModeSwitchItems((ModeSwitch) item, modes, targetClass, filter, itemList);
} else if (item instanceof ProbabilitySwitch) {
// **** ProbabilitySwitch
for (ProbabilitySwitchEntry pse : ((ProbabilitySwitch) item).getEntries()) {
collectActivityGraphItems(pse.getItems(), modes, targetClass, filter, itemList);
}
} else if (targetClass.isInstance(item)) {
T castedItem = targetClass.cast(item);
if (filter == null || filter.apply(castedItem)) {
itemList.add(castedItem);
}
}
}
}
private static <T extends ActivityGraphItem> void collectWhileLoopItems(final WhileLoop loop, final EMap<ModeLabel, String> modes,
final Class<T> targetClass, final Function<T, Boolean> filter, final List<T> itemList) {
collectActivityGraphItems(loop.getItems(), modes, targetClass, filter, itemList);
}
private static <T extends ActivityGraphItem> void collectSwitchItems(final Switch genericSwitch, final EMap<ModeLabel, String> modes,
final Class<T> targetClass, final Function<T, Boolean> filter, final List<T> itemList) {
boolean includeDefault = true;
for (SwitchEntry se : genericSwitch.getEntries()) {
if (modes == null) {
collectActivityGraphItems(se.getItems(), modes, targetClass, filter, itemList);
} else if (conditionIsSatisfiedBy(se.getCondition(), modes)) {
collectActivityGraphItems(se.getItems(), modes, targetClass, filter, itemList);
includeDefault = false;
break;
}
}
if (includeDefault && genericSwitch.getDefaultEntry() != null) {
collectActivityGraphItems(genericSwitch.getDefaultEntry().getItems(), modes, targetClass, filter, itemList);
}
}
private static <T extends ActivityGraphItem> void collectModeSwitchItems(final ModeSwitch modeSwitch, final EMap<ModeLabel, String> modes,
final Class<T> targetClass, final Function<T, Boolean> filter, final List<T> itemList) {
boolean includeDefault = true;
for (ModeSwitchEntry mse : modeSwitch.getEntries()) {
if (modes == null) {
collectActivityGraphItems(mse.getItems(), modes, targetClass, filter, itemList);
} else if (mse.getCondition().isSatisfiedBy(modes)) {
collectActivityGraphItems(mse.getItems(), modes, targetClass, filter, itemList);
includeDefault = false;
break;
}
}
if (includeDefault && modeSwitch.getDefaultEntry() != null) {
collectActivityGraphItems(modeSwitch.getDefaultEntry().getItems(), modes, targetClass, filter, itemList);
}
}
public static boolean conditionIsSatisfiedBy(Object condition, EMap<ModeLabel, String> context) {
// no context defined => satisfied (no restriction)
if (context == null) return true;
// OR condition
if (condition instanceof ConditionDisjunction) {
return conditionIsSatisfiedBy((ConditionDisjunction) condition, context);
}
// AND condition
if (condition instanceof ConditionConjunction) {
return conditionIsSatisfiedBy((ConditionConjunction) condition, context);
}
// Compare the value of a mode label with a given value
if (condition instanceof ModeValueCondition) {
return conditionIsSatisfiedBy((ModeValueCondition) condition, context);
}
// Compare the values of two mode labels
if (condition instanceof ModeLabelCondition) {
return conditionIsSatisfiedBy((ModeLabelCondition) condition, context);
}
// no restriction for other types
return true;
}
public static boolean conditionIsSatisfiedBy(ConditionDisjunction condition, EMap<ModeLabel, String> context) {
// no context defined => satisfied (no restriction)
if (context == null) return true;
// OR condition
for (ConditionDisjunctionEntry entry : condition.getEntries()) {
if (conditionIsSatisfiedBy(entry, context)) {
return true;
}
}
return false;
}
public static boolean conditionIsSatisfiedBy(ConditionConjunction condition, EMap<ModeLabel, String> context) {
// no context defined => satisfied (no restriction)
if (context == null) return true;
// AND condition
for (Condition entry : condition.getEntries()) {
if (!conditionIsSatisfiedBy(entry, context)) {
return false;
}
}
return true;
}
public static boolean conditionIsSatisfiedBy(ModeValueCondition condition, EMap<ModeLabel, String> context) {
// no context defined => satisfied (no restriction)
if (context == null) return true;
// Compare the value of a mode label with a given value
// check completeness of specified condition
ModeLabel label = condition.getLabel();
RelationalOperator relation = condition.getRelation();
if (label == null || relation == RelationalOperator._UNDEFINED_) {
return false;
}
// no value specified in context => satisfied (no restriction)
String labelValue = context.get(label);
return (labelValue == null)
|| isTrue(label, label, relation, labelValue, condition.getValue());
}
public static boolean conditionIsSatisfiedBy(ModeLabelCondition condition, EMap<ModeLabel, String> context) {
// no context defined => satisfied (no restriction)
if (context == null) return true;
// Compare the values of two mode labels
// check completeness of specified condition
ModeLabel label1 = condition.getLabel1();
ModeLabel label2 = condition.getLabel2();
RelationalOperator relation = condition.getRelation();
if (label1 == null || label2 == null || relation == RelationalOperator._UNDEFINED_) {
return false;
}
// no value specified in context => satisfied (no restriction)
String labelValue1 = context.get(label1);
String labelValue2 = context.get(label2);
return labelValue1 == null || labelValue2 == null
|| isTrue(label1, label2, relation, labelValue1, labelValue2);
}
private static boolean isTrue(ModeLabel label1, ModeLabel label2, RelationalOperator relation,
String labelValue1, String labelValue2) {
// check availability of modes and compatibility of mode label types
if (label1 == null || label1.getMode() == null
|| label2 == null || label2.getMode() == null
|| label1.getMode() != label2.getMode()) {
return false;
}
if (label1.getMode() instanceof EnumMode) {
ModeLiteral literal1 = ((EnumMode) label1.getMode()).getLiteral(labelValue1);
ModeLiteral literal2 = ((EnumMode) label2.getMode()).getLiteral(labelValue2);
if (literal1 == null || literal2 == null) {
return false;
}
switch (relation) {
case EQUAL:
return literal1 == literal2;
case NOT_EQUAL:
return literal1 != literal2;
default:
break;
}
}
if (label1.getMode() instanceof NumericMode) {
Integer int1 = Ints.tryParse(labelValue1);
Integer int2 = Ints.tryParse(labelValue2);
if (int1 == null || int2 == null) {
return false;
}
switch (relation) {
case EQUAL:
return int1.equals(int2);
case NOT_EQUAL:
return ! int1.equals(int2);
case GREATER_THAN:
return int1 > int2;
case LESS_THAN:
return int1 < int2;
default:
break;
}
}
return false;
}
/**
* Returns a set of labels accessed from the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getAccessedLabelSet(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class)
.stream().map(LabelAccess::getData).filter(Objects::nonNull).collect(Collectors.toSet());
}
/**
* Returns a set of labels read by the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getReadLabelSet(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class, (la -> la.getAccess() == READ))
.stream().map(LabelAccess::getData).filter(Objects::nonNull).collect(Collectors.toSet());
}
/**
* Returns a set of labels written by the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getWriteLabelSet(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class, (la -> la.getAccess() == WRITE))
.stream().map(LabelAccess::getData).filter(Objects::nonNull).collect(Collectors.toSet());
}
/**
* Returns a list of all label accesses of the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of LabelAccesses
*/
public static List<LabelAccess> getLabelAccessList(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class);
}
/**
* Returns a list of read label accesses of the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of LabelAccesses
*/
public static List<LabelAccess> getReadLabelAccessList(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class, (la -> la.getAccess() == READ));
}
/**
* Returns a list of write label accesses of the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of LabelAccesses
*/
public static List<LabelAccess> getWriteLabelAccessList(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class, (la -> la.getAccess() == WRITE));
}
/**
* Returns a map: labels accessed from runnable -&gt; the corresponding label accesses
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccesses
*/
public static Map<Label, List<LabelAccess>> getLabelToLabelAccessMap(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class, (la -> la.getData() != null))
.stream().collect(Collectors.groupingBy(LabelAccess::getData));
}
/**
* Returns a map: labels accessed by the runnable -&gt; the corresponding LabelAccessStatistics
* @param runnable runnable
* @param modes (optional) - null works
* @return Map:
* Label -&gt; List of LabelAccessStatistics
*/
public static Map<Label, List<LabelAccessStatistic>> getLabelAccessStatisticsMap(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class,
(la -> la.getData() != null && la.getStatistic() != null))
.stream().collect(Collectors.groupingBy(
LabelAccess::getData,
Collectors.mapping(LabelAccess::getStatistic, Collectors.toList()) ));
}
/**
* Returns a map: labels read by the runnable -&gt; the corresponding LabelAccessStatistics
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccessStatistics
*/
public static Map<Label, List<LabelAccessStatistic>> getReadLabelAccessStatisticsMap(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class,
(la -> la.getData() != null && la.getStatistic() != null && la.getAccess() == READ))
.stream().collect(Collectors.groupingBy(
LabelAccess::getData,
Collectors.mapping(LabelAccess::getStatistic, Collectors.toList()) ));
}
/**
* Returns a map: labels written by the runnable -&gt; the corresponding LabelAccessStatistics
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccessStatistics
*/
public static Map<Label, List<LabelAccessStatistic>> getWriteLabelAccessStatisticsMap(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, LabelAccess.class,
(la -> la.getData() != null && la.getStatistic() != null && la.getAccess() == WRITE))
.stream().collect(Collectors.groupingBy(
LabelAccess::getData,
Collectors.mapping(LabelAccess::getStatistic, Collectors.toList()) ));
}
/**
* Returns a set of labels accessed by the process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getAccessedLabelSet(Process process, EMap<ModeLabel, String> modes) {
HashSet<Label> result = new HashSet<>();
for (Runnable r : getRunnableList(process, modes))
result.addAll(getAccessedLabelSet(r, modes));
return result;
}
/**
* Returns a set of labels read by the process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getReadLabelSet(Process process, EMap<ModeLabel, String> modes) {
HashSet<Label> result = new HashSet<>();
for (Runnable r : getRunnableList(process, modes))
result.addAll(getReadLabelSet(r, modes));
return result;
}
/**
* Returns a set of labels written by the process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Label> getWriteLabelSet(Process process, EMap<ModeLabel, String> modes) {
HashSet<Label> result = new HashSet<>();
for (Runnable r : getRunnableList(process, modes))
result.addAll(getWriteLabelSet(r, modes));
return result;
}
/**
* Returns a list of all label accesses of the process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of LabelAccesses
*/
public static List<LabelAccess> getLabelAccessList(Process process, EMap<ModeLabel, String> modes) {
ArrayList<LabelAccess> result = new ArrayList<>();
for (Runnable r : getRunnableList(process, modes))
result.addAll(getLabelAccessList(r, modes));
return result;
}
/**
* Returns a map: accessed labels of the process -&gt; the corresponding label accesses
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccess
*/
public static Map<Label, List<LabelAccess>> getLabelToLabelAccessMap(Process process, EMap<ModeLabel, String> modes) {
HashMap<Label, List<LabelAccess>> result = new HashMap<>();
for (Runnable run : getRunnableList(process, modes)) {
Map<Label, List<LabelAccess>> labelToLabelAccessMap = SoftwareUtil.getLabelToLabelAccessMap(run, modes);
for(Entry<Label, List<LabelAccess>> entry : labelToLabelAccessMap.entrySet()) {
Label label = entry.getKey();
List<LabelAccess> accesses = entry.getValue();
List<LabelAccess> accessList = result.computeIfAbsent(label, k -> new ArrayList<>());
accessList.addAll(accesses);
}
}
return result;
}
/**
* Returns a map: labels accessed by the process -&gt; the corresponding label access statistics
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccessStatistic
*/
public static Map<Label, List<LabelAccessStatistic>> getLabelAccessStatisticsMap(Process process, EMap<ModeLabel, String> modes) {
HashMap<Label, List<LabelAccessStatistic>> result = new HashMap<>();
for (Runnable r : getRunnableList(process, modes)) {
Map<Label, List<LabelAccessStatistic>> labelToLabelAccessMap = SoftwareUtil.getLabelAccessStatisticsMap(r, modes);
for(Entry<Label, List<LabelAccessStatistic>> entry : labelToLabelAccessMap.entrySet()) {
Label label = entry.getKey();
List<LabelAccessStatistic> statistics = entry.getValue();
List<LabelAccessStatistic> statisticsList = result.computeIfAbsent(label, k -> new ArrayList<>());
statisticsList.addAll(statistics);
}
}
return result;
}
/**
* Returns a map: labels read the process -&gt; the corresponding label access statistics
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccessStatistic
*/
public static Map<Label, List<LabelAccessStatistic>> getReadLabelAccessStatisticsMap(Process process, EMap<ModeLabel, String> modes) {
HashMap<Label, List<LabelAccessStatistic>> result = new HashMap<>();
for (Runnable run : getRunnableList(process, modes)) {
Map<Label, List<LabelAccessStatistic>> readLabelAccessStatisticsMap = SoftwareUtil.getReadLabelAccessStatisticsMap(run, modes);
for(Entry<Label, List<LabelAccessStatistic>> entry : readLabelAccessStatisticsMap.entrySet()) {
Label label = entry.getKey();
List<LabelAccessStatistic> statistics = entry.getValue();
List<LabelAccessStatistic> statisticsList = result.computeIfAbsent(label, k -> new ArrayList<>());
statisticsList.addAll(statistics);
}
}
return result;
}
/**
* Returns a map: labels written by the process -&gt; the corresponding label access statistics
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Map: Label -&gt; List of LabelAccessStatistic
*/
public static Map<Label, List<LabelAccessStatistic>> getWriteLabelAccessStatisticsMap(Process process, EMap<ModeLabel, String> modes) {
HashMap<Label, List<LabelAccessStatistic>> result = new HashMap<>();
for (Runnable run : getRunnableList(process, modes)) {
Map<Label, List<LabelAccessStatistic>> writeLabelAcessStatisticsMap = SoftwareUtil.getWriteLabelAccessStatisticsMap(run, modes);
for(Entry<Label, List<LabelAccessStatistic>> entry : writeLabelAcessStatisticsMap.entrySet()) {
Label label = entry.getKey();
List<LabelAccessStatistic> statistics = entry.getValue();
List<LabelAccessStatistic> statisticsList = result.computeIfAbsent(label, k -> new ArrayList<>());
statisticsList.addAll(statistics);
}
}
return result;
}
/**
* Returns the reads from a process to a certain label. Evaluates the LabelAccessStatistic.
* Definition of TimeType is possible. Null value returns the average case.
*/
public static float getLabelReadCount(Label label, Process process, EMap<ModeLabel, String> modes, TimeType timeType) {
if (timeType == null)
timeType = TimeType.ACET;
EList<@NonNull LabelAccess> accessList = collectActivityGraphItems(
process.getActivityGraph(),
modes,
LabelAccess.class,
(la -> la.getAccess() == READ && la.getData() == label));
return sumUpLabelAccesses(timeType, accessList);
}
/**
* Returns the writes from a process to a certain label. Evaluates the LabelAccessStatistic.
* Definition of TimeType is possible. Null value returns the average case.
*/
public static float getLabelWriteCount(Label label, Process process, EMap<ModeLabel, String> modes, TimeType timeType) {
if (timeType == null)
timeType = TimeType.ACET;
EList<@NonNull LabelAccess> accessList = collectActivityGraphItems(
process.getActivityGraph(),
modes,
LabelAccess.class,
(la -> la.getAccess() == WRITE && la.getData() == label));
return sumUpLabelAccesses(timeType, accessList);
}
private static float sumUpLabelAccesses(TimeType timeType, EList<@NonNull LabelAccess> accessList) {
float accesses = 0f;
for (LabelAccess la : accessList) {
if (la.getStatistic() == null || la.getStatistic().getValue() == null) {
accesses += 1f;
continue;
}
NumericStatistic statistic = la.getStatistic().getValue();
if (statistic instanceof SingleValueStatistic) {
accesses += ((SingleValueStatistic) statistic).getValue();
} else if (statistic instanceof MinAvgMaxStatistic) {
MinAvgMaxStatistic stat = (MinAvgMaxStatistic) statistic;
switch (timeType) {
case ACET:
accesses += stat.getAvg();
break;
case BCET:
accesses += stat.getMin();
break;
case WCET:
accesses += stat.getMax();
break;
}
}
}
return accesses;
}
/**
* Returns a list of runnables called by the process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of Runnables
*/
public static List<Runnable> getRunnableList(Process process, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(process.getActivityGraph(), modes, RunnableCall.class)
.stream().map(RunnableCall::getRunnable).filter(Objects::nonNull).collect(Collectors.toList());
}
/**
* Returns a set of runnables called by the process - no duplicates
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Set of runnables called by the process
*/
public static Set<Runnable> getRunnableSet(Process process, EMap<ModeLabel, String> modes) {
return new HashSet<>(getRunnableList(process, modes));
}
/**
* Returns the number of label accesses from a statistic.
* The accType defines if the minimum, maximum or average accesses are returned.
*/
public static float getLabelAccessCountFromStatistics(LabelAccess labelAcc, TimeType accType) {
if (labelAcc.getStatistic() == null)
return 1;
float accesses = 1;
final NumericStatistic value = labelAcc.getStatistic().getValue();
if (value instanceof SingleValueStatistic) {
accesses = ((SingleValueStatistic)value).getValue();
} else if (value instanceof MinAvgMaxStatistic) {
switch(accType) {
case ACET:
accesses = ((MinAvgMaxStatistic)value).getAvg();
break;
case BCET:
accesses = ((MinAvgMaxStatistic)value).getMin();
break;
case WCET:
accesses = ((MinAvgMaxStatistic)value).getMax();
break;
default:
accesses = ((MinAvgMaxStatistic)value).getAvg();
}
}
return accesses;
}
/**
* Returns a list of runnables reading the label
* @param label label
* @param modes (optional) - null works
* @return
* List of Runnables
*/
public static List<Runnable> getReaderListOfLabel(Label label, EMap<ModeLabel, String> modes) {
ArrayList<Runnable> result = new ArrayList<>();
for (LabelAccess la : label.getLabelAccesses()) {
if (la.getAccess() == LabelAccessEnum.READ) {
Runnable run = AmaltheaServices.getContainerOfType(la, Runnable.class);
if (modes == null || modes.isEmpty() || (collectActivityGraphItems(run.getActivityGraph(), modes)).contains(la)) {
result.add(AmaltheaServices.getContainerOfType(la, Runnable.class));
}
}
}
return result;
}
/**
* Returns a set of runnables reading the label
* @param label label
* @param modes (optional) - null works
* @return
* Set of Labels
*/
public static Set<Runnable> getReadersSetOfLabel(Label label, EMap<ModeLabel, String> modes) {
return new HashSet<>(getReaderListOfLabel(label, modes));
}
/**
* Returns a list of runnables writing the label
* @param label label
* @param modes (optional) - null works
* @return
* List of Runnables
*/
public static List<Runnable> getWriterListOfLabel(Label label, EMap<ModeLabel, String> modes) {
ArrayList<Runnable> result = new ArrayList<>();
for (LabelAccess la : label.getLabelAccesses()) {
if (la.getAccess().equals(LabelAccessEnum.WRITE)) {
Runnable run = AmaltheaServices.getContainerOfType(la, Runnable.class);
if (modes == null || modes.isEmpty() || (collectActivityGraphItems(run.getActivityGraph(), modes)).contains(la)) {
result.add(AmaltheaServices.getContainerOfType(la, Runnable.class));
}
}
}
return result;
}
/**
* Returns a set of runnables writing the label
* @param label label
* @param modes (optional) - null works
* @return
* Set of Runnables
*/
public static Set<Runnable> getWriterSetOfLabel(Label label, EMap<ModeLabel, String> modes) {
return new HashSet<>(getWriterListOfLabel(label, modes));
}
/**
* Collects a list of set events calls for a process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of SetEvents
*/
public static List<SetEvent> collectSetEvents(Process process, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(process.getActivityGraph(), modes, SetEvent.class);
}
/**
* Collects a list of clear event calls for a process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of ClearEvents
*/
public static List<ClearEvent> collectClearEvents(Process process, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(process.getActivityGraph(), modes, ClearEvent.class);
}
/**
* Collects a list of wait event calls for a process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of WaitEvents
*/
public static List<WaitEvent> collectWaitEvents(Process process, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(process.getActivityGraph(), modes, WaitEvent.class);
}
/**
* Collects a list of event calls (clear, set or wait) of a process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of CallSequenceItems
*/
public static List<ActivityGraphItem> collectEventsOfProcess(Process process, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(process.getActivityGraph(), modes,
(call -> call instanceof ClearEvent || call instanceof SetEvent || call instanceof WaitEvent));
}
/**
* Returns a list of all exchanged labels that are written by the sender process and read by the receiver process
* @param sender process (Task or ISR)
* @param receiver process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of Labels
*/
public static List<Label> getInterTaskCommunication(Process sender, Process receiver, EMap<ModeLabel, String> modes) {
ArrayList<Label> result = new ArrayList<>();
result.addAll(getWriteLabelSet(sender, modes));
result.retainAll(getReadLabelSet(receiver, modes));
return result;
}
/**
* Returns a list of processes calling the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of Processes
*/
public static List<Process> getCallingProcesses(Runnable runnable, EMap<ModeLabel, String> modes) {
ArrayList<Process> result = new ArrayList<>();
for (RunnableCall callerRC : runnable.getRunnableCalls()) {
IExecutable caller = callerRC.getContainingExecutable(); // null if container is not of type IExecutable
if (!(caller instanceof Process)) continue;
Process proc = (Process) caller;
if (modes != null && !modes.isEmpty()) {
for (RunnableCall rc : collectActivityGraphItems(caller.getActivityGraph(), modes, RunnableCall.class)) {
if (rc.getRunnable() == runnable) {
result.add(proc);
break;
}
}
} else {
result.add(proc);
}
}
return result;
}
/**
* Returns a list of runnables directly calling the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of Runnables
*/
public static List<Runnable> getCallingRunnables(Runnable runnable, EMap<ModeLabel, String> modes) {
ArrayList<Runnable> result = new ArrayList<>();
for (RunnableCall callerRC : runnable.getRunnableCalls()) {
IExecutable caller = callerRC.getContainingExecutable(); // null if container is not of type IExecutable
if (!(caller instanceof Runnable)) continue;
Runnable run = (Runnable) caller;
if (modes != null && !modes.isEmpty()) {
for (RunnableCall rc : collectActivityGraphItems(caller.getActivityGraph(), modes, RunnableCall.class)) {
if (rc.getRunnable() == runnable) {
result.add(run);
break;
}
}
}
else
result.add(run);
}
return result;
}
/**
* Returns a list of runnables directly called by the runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of Runnables
*/
public static List<Runnable> getCalledRunnables(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, RunnableCall.class)
.stream().map(RunnableCall::getRunnable).filter(Objects::nonNull).collect(Collectors.toList());
}
/**
* Returns a list of all execution needs for a given runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of ExecutionNeeds
*/
public static List<ExecutionNeed> getExecutionNeeds(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, ExecutionNeed.class);
// Should nested runnable calls also be included ? (potential cycles)
}
/**
* Returns a list of all execution needs for a given process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of ExecutionNeeds
*/
public static List<ExecutionNeed> getExecutionNeeds(Process process, EMap<ModeLabel, String> modes) {
List<ExecutionNeed> result = new ArrayList<>();
// add needs on process level
result.addAll(collectActivityGraphItems(process.getActivityGraph(), modes, ExecutionNeed.class));
// add needs of called runnables
for (Runnable run : getRunnableList(process, modes)) {
result.addAll(getExecutionNeeds(run, modes));
}
return result;
}
/**
* Returns a list of all ticks for a given runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* List of Ticks
*/
public static List<Ticks> getTicks(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, Ticks.class);
// Should nested runnable calls also be included ? (potential cycles)
}
/**
* Returns a list of all ticks for a given process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* List of Ticks
*/
public static List<Ticks> getTicks(Process process, EMap<ModeLabel, String> modes) {
List<Ticks> result = new ArrayList<>();
// add ticks on process level
result.addAll(collectActivityGraphItems(process.getActivityGraph(), modes, Ticks.class));
// add ticks of called runnables
for(Runnable run : getRunnableList(process, modes)) {
result.addAll(getTicks(run, modes));
}
return result;
}
/**
* Returns a set of server calls for a runnable
* @param runnable runnable
* @param modes (optional) - null works
* @return
* Set of ServerCall
*/
public static Set<ServerCall> getServerCallSet(Runnable runnable, EMap<ModeLabel, String> modes) {
return collectActivityGraphItems(runnable.getActivityGraph(), modes, ServerCall.class).stream().collect(Collectors.toSet());
}
/**
* Returns a set of server calls for a process
* @param process process (Task or ISR)
* @param modes (optional) - null works
* @return
* Set of ServerCall
*/
public static Set<ServerCall> getServerCallSet(Process process, EMap<ModeLabel, String> modes) {
HashSet<ServerCall> result = new HashSet<>();
for (Runnable run : getRunnableList(process, modes)) {
result.addAll(getServerCallSet(run, modes));
}
return result;
}
}