diff --git a/org.fortiss.af3.exploration.alg/master/META-INF/MANIFEST.MF b/org.fortiss.af3.exploration.alg/master/META-INF/MANIFEST.MF index e93a0577e4d5773cd691ef92e9043e06b2af95a5..ee717b8d5db96743b79782935808114107f75ab1 100644 --- a/org.fortiss.af3.exploration.alg/master/META-INF/MANIFEST.MF +++ b/org.fortiss.af3.exploration.alg/master/META-INF/MANIFEST.MF @@ -182,4 +182,5 @@ Export-Package: com.google.common.annotations, org.fortiss.af3.exploration.moea.model.solutions.impl, org.fortiss.af3.exploration.moea.model.solutions.util, org.fortiss.af3.exploration.moea.model.util, + org.fortiss.af3.exploration.port, org.fortiss.af3.exploration.util diff --git a/org.fortiss.af3.exploration.alg/master/src/org/fortiss/af3/exploration/port/DSEPortingUtils.java b/org.fortiss.af3.exploration.alg/master/src/org/fortiss/af3/exploration/port/DSEPortingUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..fe64d7e805a557c88e3f7f1c309d1931ada6fca9 --- /dev/null +++ b/org.fortiss.af3.exploration.alg/master/src/org/fortiss/af3/exploration/port/DSEPortingUtils.java @@ -0,0 +1,430 @@ +/*--------------------------------------------------------------------------+ +$Id: codetemplates.xml 1 2011-01-01 00:00:01Z hoelzl $ +| | +| Copyright 2017 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.af3.exploration.port; + +import static org.fortiss.af3.exploration.alg.dse.sysmodel.arch.IResourceConnectionAdapter.ConnectionType.BIDIRECTIONAL; +import static org.fortiss.af3.platform.utils.PlatformArchitectureUtils.getReferencedElementsWithType; +import static org.fortiss.tooling.common.util.LambdaUtils.filterStream; +import static org.fortiss.tooling.common.util.LambdaUtils.getFirst; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.getChildrenWithType; +import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickFirstInstanceOf; +import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getParentElement; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.conqat.lib.commons.collections.Pair; +import org.fortiss.af3.component.model.Component; +import org.fortiss.af3.component.model.ComponentArchitecture; +import org.fortiss.af3.component.model.OutputPort; +import org.fortiss.af3.component.model.Port; +import org.fortiss.af3.exploration.alg.dse.sysmodel.arch.IResourceConnectionAdapter.ConnectionType; +import org.fortiss.af3.exploration.alg.dse.sysmodel.arch.SystemParameterContainer; +import org.fortiss.af3.exploration.dsl_v2.model.booleanp.allocation.Allocation; +import org.fortiss.af3.exploration.extension.IDseInputParameters.DeployableComponents; +import org.fortiss.af3.exploration.extension.IDseInputParameters.SignalType; +import org.fortiss.af3.exploration.extension.IDseInputParameters.TemporalTriggers; +import org.fortiss.af3.exploration.model.ExplorationSpecification; +import org.fortiss.af3.exploration.moea.model.annotation.ComponentDiverseImplRef; +import org.fortiss.af3.exploration.projectmodel.DSE; +import org.fortiss.af3.expression.model.types.TBool; +import org.fortiss.af3.expression.model.types.TDouble; +import org.fortiss.af3.expression.model.types.TInt; +import org.fortiss.af3.platform.model.ExecutionUnit; +import org.fortiss.af3.platform.model.IPhysicalPlatformArchitectureElement; +import org.fortiss.af3.platform.model.IPlatformArchitectureElement; +import org.fortiss.af3.platform.model.IPlatformResource; +import org.fortiss.af3.platform.model.IVirtualizationPlatformArchitectureElement; +import org.fortiss.af3.platform.model.PlatformArchitecture; +import org.fortiss.af3.platform.model.TransmissionUnit; +import org.fortiss.af3.platform.utils.PlatformArchitectureUtils; +import org.fortiss.af3.project.model.FileProject; +import org.fortiss.af3.project.model.typesystem.IType; +import org.fortiss.af3.task.model.TaskAllocation; +import org.fortiss.af3.task.model.TaskArchitecture; +import org.fortiss.tooling.base.model.element.IConnector; +import org.fortiss.tooling.base.model.element.IModelElement; +import org.fortiss.tooling.kernel.utils.EcoreUtils; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +/** + * + * @author diewald + * @author $Author: hoelzl $ + * @version $Rev: 18709 $ + * @ConQAT.Rating RED Hash: + */ +public class DSEPortingUtils { + /** + * Lookup table for to determine the direction of a connection by the type of the target + * {@link IConnector}. + */ + // TODO: UsePlatformPort? + public static Map<Class<? extends IConnector>, ConnectionType> connectionTypeLUT = Collections + .unmodifiableMap(new HashMap<Class<? extends IConnector>, ConnectionType>() { + { + } + }); + + /** + * Returns the type of communication the given port can handle: incoming, outgoing, or + * bidirectional traffic. + * + * @param sourceConnector + * {@link IConnector} to be examined. + * @return The port type (default = bidirectional). + */ + public static ConnectionType getPortDirection(IConnector sourceConnector) { + ConnectionType connectionTypeSource = connectionTypeLUT.get(sourceConnector.getClass()); + return connectionTypeSource != null ? connectionTypeSource : BIDIRECTIONAL; + } + + /** + * Creates a collection of deployment targets (that are {@link ExecutionUnit}s) from the given + * collection of {@code platformArchitecture}s. Therefore, the {@link DeploymentGranularity} + * annotation is examined for each {@link ExecutionUnit} present in the given Platforms. + * + * @param platformArchitectures + * for which to extract the collection of deployment {@link ExecutionUnit}s. + * @return collection of deployment targets. + * @throws Exception + * if an invalid combination of {@link DeploymentGranularity} specifications has + * been detected. + */ + public static Collection<ExecutionUnit> createDeploymentTargets( + Collection<PlatformArchitecture> platformArchitectures) throws Exception { + Collection<ExecutionUnit> rval = new HashSet<>(); + + FileProject prj = + getParentElement(getFirst(platformArchitectures, x -> true).get(), + FileProject.class, false); + DSE af3DSE = pickFirstInstanceOf(DSE.class, prj.getRootElements()); + + ExplorationSpecification expSpec = af3DSE.getExplorationSpecification(); + + Collection<Allocation> allocConstrSet = + EcoreUtils.getChildrenWithType(expSpec, Allocation.class); + for(Allocation alloc : allocConstrSet) { + Collection<IModelElement> targetElementSet = + alloc.getRight().getSetReference().getEntries(); + filterStream(targetElementSet, e -> e instanceof ExecutionUnit).map( + ExecutionUnit.class::cast).forEach(e -> rval.add(e)); + } + + // for(PlatformArchitecture curPA : platformArchitectures) { + // for(DeploymentGranularity deplAnn : getChildrenWithType(curPA, + // DeploymentGranularity.class)) { + // IModelElement execUnit = deplAnn.getSpecificationOf(); + // + // // If the current deployment target is a virtual ExecutionUnit, e.g. a partition, + // // ensure that none its referenced physical ExecutionUnits (or any of theri parents) + // // are also selected as deployment targets. + // if(execUnit instanceof IVirtualizationPlatformArchitectureElement && + // execUnit instanceof ExecutionUnit) { + // for(IHierarchicElement currentHardwareResource : getReferencedElementsWithType( + // execUnit, IHierarchicElement.class)) { + // if(isAnyParentDeploymentTarget(currentHardwareResource)) { + // String refHwResourceName = currentHardwareResource.toString(); + // if(currentHardwareResource instanceof INamedElement) { + // refHwResourceName = + // ((INamedElement)currentHardwareResource).getName() + + // "(id: " + + // ((INamedElement)currentHardwareResource).getId() + + // ")"; + // } + // throw new Exception("The referenced hardware resource " + + // refHwResourceName + + // " or one of its containers of the virtual element " + + // ((ExecutionUnit)execUnit).getName() + "(id: " + + // ((ExecutionUnit)execUnit).getId() + + // ") has been chosen as a deployment target.\n" + + // "This is not allowed for elements with a virtualization layer."); + // } + // } + // } + // + // if(execUnit instanceof ExecutionUnit && deplAnn.isIsDeploymentTarget()) { + // rval.add((ExecutionUnit)execUnit); + // } + // } + // } + + if(rval.isEmpty()) { + throw new Exception( + "No deployment targets have been specified in the target platform architecture(s)." + + " Please check whether the correct platform architecture was selected and whether" + + " the desired Execution Units were selected as deployment targets" + + " (Platform Model --> Annotation View --> Deployment Target)"); + } + + return rval; + } + + // TODO: Why is the FailureRate annotation bound to IPhysicalPlatformElement instead of + // IPlatformResource? + /** + * Creates a Map that relates all annotated {@link IPlatformArchitectureElement}s with their + * specified {@link FailureRate}. + */ + public static Map<IPlatformArchitectureElement, Double> createFailureRateMap( + Collection<PlatformArchitecture> platformArchitectures) throws Exception { + Map<IPlatformArchitectureElement, Double> failureRateMap = new HashMap<>(); + for(PlatformArchitecture pa : platformArchitectures) { + for(IPlatformArchitectureElement platformElement : getChildrenWithType(pa, + IPlatformArchitectureElement.class)) { + failureRateMap.put(platformElement, getResourceFailureRate(platformElement)); + } + } + + return failureRateMap; + } + + /** + * Extracts the failure probability of a given {@link IPlatformResource}. If the + * {@code resourceElement} is a {@link IVirtualizationPlatformArchitectureElement}, the average + * value of the referenced {@link IPhysicalPlatformArchitectureElement}s is used. + * + * @param resourceElement + * resource for which to determine the failure probability. + * @return failure probability of the given {@code resourceElement}. + * @throws Exception + * if the failure probability is not correctly defined in the model. + */ + // TODO: check, whether it make sense to move the failure rate annotation to the AF3 platform + // since it would allow a simple analysis of hierarchical platforms. + public static Double getResourceFailureRate(IPlatformArchitectureElement resourceElement) + throws Exception { + + // If the annotated element is a part of the system software, the resource links are used to + // determine the speed of the associated resources. + if(resourceElement instanceof IVirtualizationPlatformArchitectureElement) { + Collection<IPhysicalPlatformArchitectureElement> associatedResources = + getReferencedElementsWithType(resourceElement, + IPhysicalPlatformArchitectureElement.class); + + if(!(associatedResources.isEmpty())) { + Double avgFailureRate = Double.valueOf(0); + for(IPhysicalPlatformArchitectureElement currentAssociatedResource : associatedResources) { + if(currentAssociatedResource instanceof IModelElement) { + // FIXME: For now, just use a default value. + return 10E-6; + // FailureRate failureRateAnnotation = + // getAnnotation((IModelElement)currentAssociatedResource, + // FailureRate.class); + // + // if(failureRateAnnotation != null) { + // avgFailureRate += failureRateAnnotation.getFailureRate_FIT(); + // } else { + // throw new Exception("The platform resource " + + // currentAssociatedResource + + // " does not have a failure rate annotation."); + // } + } + } + + return avgFailureRate / associatedResources.size(); + } else if(resourceElement instanceof ExecutionUnit) { + // For now the failure rates are only evaluated for ExecutionUnits, so the failure + // rate annotation is only required for these resources. + throw new Exception("The virtual resource " + resourceElement.toString() + + " does not reference a physical resource"); + } + } else { + // FIXME: For now, just use a default value. + return 10E-6; + // FailureRate failureRateAnnotation = + // pickFirstInstanceOf(FailureRate.class, + // ((IModelElement)resourceElement).getSpecifications()); + // + // if(failureRateAnnotation != null) { + // return failureRateAnnotation.getFailureRate_FIT(); + // } + // throw new Exception("The platform resource " + resourceElement + + // " does not have a failure rate annotation."); + } + + return null; + // throw new Exception("The failure rate for the platform resource " + resourceElement + + // " coult not be determined."); + } + + /** + * Creates a map of all {@link IPlatformResource} which have an annotated power consumption + * value and their specified value. + */ + public static Map<IPlatformResource, Double> createPowerConsumptionMap( + Collection<PlatformArchitecture> platformArchitectures) throws Exception { + Map<IPlatformResource, Double> powerConsumptionMap = new HashMap<>(); + powerConsumptionMap.putAll(getTransmissionUnitPowerConsumption(platformArchitectures)); + return powerConsumptionMap; + } + + /** Maps all {@link TransmissionUnit}s to their annotated power consumption value. */ + // TODO: We need a way to define the energy consumed by transmission units like busses: stand-by + // + active. Currently, we hard-code the consumed energy while a transmission Unit is active + // while we assue that it does not consume energy in the idle state. + public static Map<IPlatformResource, Double> getTransmissionUnitPowerConsumption( + Collection<PlatformArchitecture> platformArchitectures) { + Map<IPlatformResource, Double> powerConsumptionMap = new HashMap<>(); + for(PlatformArchitecture pa : platformArchitectures) { + for(TransmissionUnit tu : getChildrenWithType(pa, TransmissionUnit.class)) { + powerConsumptionMap.put(tu, 1.0); + } + } + + return powerConsumptionMap; + } + + /** + * Maps all deployable {@link Component}s to their specified periodicities. Non-periodic + * {@link Component} are not supported. + */ + // FIXME: The period is hard-coded here. It must be taken from the yet-to-come timing model. + public static Map<Component, Double> createComponentPeriodMap( + Collection<Component> deployableComponents) { + Map<Component, Double> componentPeriodMap = new HashMap<>(); + for(Component deployableComponent : deployableComponents) { + componentPeriodMap.put(deployableComponent, 10.0); + } + return componentPeriodMap; + } + + /** + * Maps all "abstract" and deployable {@link Component}s the set of {@link Component}s which are + * selected as their diverse implementations by means of the {@link ComponentDiverseImplRef} + * annotation. + */ + public static Multimap<Component, Component> createComponentReplacementMap( + Collection<Component> deployableComponent) { + Multimap<Component, Component> replacementComponentMap = HashMultimap.create(); + for(Component component : deployableComponent) { + // ComponentDiverseImplRef componentReplacementRef = + // AnnotationUtils.getAnnotation(component, ComponentDiverseImplRef.class); + // replacementComponentMap.putAll(component, componentReplacementRef.getComponentRef()); + replacementComponentMap.putAll(component, Collections.emptyList()); + } + return replacementComponentMap; + } + + /** + * Maps all deployable {@link Component}s to their amount of minimal required and maximally + * allowed replicas. A value of 1 implies that the component is present only once (without + * actual replica in the resulting solution calculated by the DSE). + */ + // FIXME: + public static Map<Component, Pair<Integer, Integer>> createComponentReplicationMap( + Collection<Component> deployableComponents) throws Exception { + Map<Component, Pair<Integer, Integer>> replicationBoundMap = new HashMap<>(); + for(Component component : deployableComponents) { + // TODO: where shall the replication bound be placed? ComponentArchitecture, + // TaskArchitecture? + // ReplicationBounds replicationBounds = getAnnotation(component, + // ReplicationBounds.class); + // if(replicationBounds == null) { + // throw new Exception("The replication bounds of the component " + + // component.getName() + " is not defined."); + // } + Pair<Integer, Integer> minMaxBounds = new Pair<>(1, 1); + replicationBoundMap.put(component, minMaxBounds); + } + + return replicationBoundMap; + } + + /** + * Returns the temporal triggers of the deployable {@link Component}s' {@link Port}s. + * + * @param deployableComponents + * Collection of {@link Component}s tthat shall be deployed. + * @return Map of the ports with a temporal trigger. + */ + public static TemporalTriggers + getPortTimingProperties(DeployableComponents deployableComponents) { + TemporalTriggers portSignalTypes = new TemporalTriggers(); + Collection<Port> allPorts = new ArrayList<>(); + for(Component currComp : deployableComponents) { + allPorts.addAll(getChildrenWithType(currComp, Port.class)); + } + allPorts.parallelStream().forEach(p -> portSignalTypes.put(p, SignalType.PERIODIC)); + return portSignalTypes; + } + + /** Maps the {@link OutputPort}s of {@link Component}s to their respective bit size. */ + public static Map<OutputPort, Long> createMessageSizeMap( + Collection<Component> deployableComponents) throws Exception { + Map<OutputPort, Long> messageSizes = new HashMap<>(); + for(Component component : deployableComponents) { + for(OutputPort port : component.getOutputPorts()) { + IType outType = port.getVariableType(); + // FIXME: Primitive fixed bit length assignments for the types. Should be done based + // on the platform. + if(outType instanceof TBool) { + messageSizes.put(port, (long)1); + } else if(outType instanceof TInt) { + messageSizes.put(port, (long)32); + } else if(outType instanceof TDouble) { + messageSizes.put(port, (long)64); + } else { + throw new Exception("No type has been defined for the output port" + port + + " that is compatible with the MOEA-based DSE exploration."); + } + } + } + + return messageSizes; + } + + /** + * Creates a container that contains all required and optional information to execute the + * MOEA-based DSE which are not AF3 standard parameters. + */ + public static SystemParameterContainer createSystemParameterContainer( + ComponentArchitecture componentArchitecture, PlatformArchitecture platformArchitecture, + TaskArchitecture taskArchitecture) throws Exception { + DeployableComponents deployableComponents = new DeployableComponents(); + // FIXME: We select the atomic components from the ComponentArchitecture to be deployed at + // the moment. Instead, the TaskArchitecture should be used here. + for(TaskAllocation taskAlloc : taskArchitecture.getTaskAllocations()) { + deployableComponents.addAll(taskAlloc.getComponents()); + } + + // Set: if we have only a hardware platform, then it will be returned by getHardwarePlatform + // --> no duplicates. + Set<PlatformArchitecture> targetPlatforms = new HashSet<>(); + targetPlatforms.add(platformArchitecture); + targetPlatforms.add(PlatformArchitectureUtils + .getPhysicalPlatformArchitecture(platformArchitecture)); + + Collection<ExecutionUnit> deploymentTargets = createDeploymentTargets(targetPlatforms); + + return new SystemParameterContainer(deployableComponents, + getPortTimingProperties(deployableComponents), deploymentTargets, + createComponentPeriodMap(deployableComponents), + createComponentReplacementMap(deployableComponents), + createComponentReplicationMap(deployableComponents), + createMessageSizeMap(deployableComponents), createFailureRateMap(targetPlatforms), + createPowerConsumptionMap(targetPlatforms), connectionTypeLUT, null, null); + } +}