package algorithms; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import models.*; import models.algebra.*; import models.dataConstraintModel.*; import models.dataFlowModel.*; /** * Algorithms to analyze data transfer model. * * @author Nitta * */ public class DataTransferModelAnalyzer { /** * Create data flow graph annotated with node attributes that indicate whether each resource state needs to be stored. * @param model a data transfer model * @return annotated data flow graph */ static public DataFlowGraph createDataFlowGraphWithStateStoringAttribute(DataTransferModel model) { DataFlowGraph graph = model.getDataFlowGraph(); Collection<Channel> channels = new HashSet<>(model.getIOChannels()); channels.addAll(model.getChannels()); for (Channel channel: channels) { for (ChannelMember member: ((DataTransferChannel) channel).getOutputChannelMembers()) { boolean toBeStored = !member.getStateTransition().isRightUnary(); // The state does not need to be stored if the state transition function is right unary. for (Node node : graph.getResourceNodes()) { if (((ResourceNode) node).getInSideResources().contains(member.getResource())) { setStoreAttribute((ResourceNode) node, toBeStored); } } } } for (Node node: graph.getResourceNodes()) { HashSet<Channel> inChannels = new HashSet<>(); for(Edge inEdge: ((ResourceNode) node).getInEdges()) { if (inEdge instanceof DataFlowEdge) { DataFlowEdge dfEdge = (DataFlowEdge) inEdge; if (dfEdge.isChannelToResource()) { inChannels.add(((ChannelNode) dfEdge.getSource()).getChannel()); } } } if ((inChannels.size() > 1)) { // If the resource has multiple input channels, then the state of the resource needs to be stored. setStoreAttribute((ResourceNode) node, true); } else if (((ResourceNode) node).getAttribute() == null) { setStoreAttribute((ResourceNode) node, false); } } return graph; } static private void setStoreAttribute(ResourceNode node, boolean toBeStored) { NodeAttribute attr = node.getAttribute(); StoreAttribute store; if (attr != null && attr instanceof NodeAttribute) { store = (StoreAttribute) attr; store.setNeeded(store.isNeeded() || toBeStored); } else { store = new StoreAttribute(); store.setNeeded(toBeStored); node.setAttribute(store); } } /** * Annotate data flow graph with edge attributes that indicate selectable data transfer methods. * @param graph a data flow graph * @return annotated data flow graph */ static public DataFlowGraph annotateWithSelectableDataTransferAttiribute(DataFlowGraph graph) { List<Node> resNodes = new ArrayList<>(graph.getResourceNodes()); // set push only attributes for (Node resNode: graph.getResourceNodes()) { if (resNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { resNodes.remove(resNode); trackEdges(resNode, resNodes); } } // set push/pull attributes to the remaining edges for (Edge e : graph.getEdges()) { if (!((DataFlowEdge) e).isChannelToResource() && ((DataFlowEdge) e).getAttribute() == null) { PushPullAttribute ppat = new PushPullAttribute(); ppat.addOption(PushPullValue.PUSHorPULL); ppat.addOption(PushPullValue.PUSH); ppat.addOption(PushPullValue.PULL); ((DataFlowEdge) e).setAttribute(ppat); } } return graph; } static private void trackEdges(Node resNode, List<Node> resNodes) { // recursively set push only attributes to input side edges for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { Node chNode = chToRes.getSource(); for (Edge resToCh : ((ChannelNode) chNode).getInEdges()) { PushPullAttribute ppat = new PushPullAttribute(); ppat.addOption(PushPullValue.PUSH); ((DataFlowEdge) resToCh).setAttribute(ppat); Node resNode2 = resToCh.getSource(); if (resNodes.contains(resNode2)) { resNodes.remove(resNode2); trackEdges(resNode2, resNodes); } } } } }