diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java index f54aea4..a392b11 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/DataTransferModelAnalyzer.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Set; import models.*; import models.algebra.*; @@ -75,12 +76,55 @@ * @return annotated data flow graph */ static public DataFlowGraph annotateWithSelectableDataTransferAttiribute(DataFlowGraph graph) { - List resNodes = new ArrayList<>(graph.getResourceNodes()); - // set push only attributes + HashSet unvisitedNodes = new HashSet<>(graph.getResourceNodes()); + // Turn push only for (Node resNode: graph.getResourceNodes()) { - if (resNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { - resNodes.remove(resNode); - trackEdges(resNode, resNodes); + if (unvisitedNodes.contains(resNode) && ((StoreAttribute) ((ResourceNode) resNode).getAttribute()).isNeeded()) { + unvisitedNodes.remove(resNode); + trackEdgesBackwardForPush(resNode, unvisitedNodes); + } + } + // Turn push/pull only with respect to channel hierarchies. + while (!unvisitedNodes.isEmpty()) { + Node resNode = unvisitedNodes.iterator().next(); + unvisitedNodes.remove(resNode); + for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + boolean pullContained = false; + Set ancestorChannels = chNode.getAncestors(); + for (ChannelNode ancestorCh: ancestorChannels) { + for (Edge resToCh: ancestorCh.getInEdges()) { + ResourceNode srcResNode = (ResourceNode) resToCh.getSource(); + DataTransferChannel ch = (DataTransferChannel) ancestorCh.getChannel(); + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.isOutside()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // To refer to outside resource. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } else { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PUSH); // For broadcasting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + unvisitedNodes.remove(srcResNode); + trackEdgesBackwardForPush(srcResNode, unvisitedNodes); + } + } + } + } + Set descendantChannels = chNode.getDescendants(); + for (ChannelNode descendantCh: descendantChannels) { + for (Edge resToCh: descendantCh.getInEdges()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); // For collecting transfer. + ((DataFlowEdge) resToCh).setAttribute(ppat); + pullContained = true; + } + } + if (pullContained) { + trackEdgesForwardForPull(resNode, unvisitedNodes); + } } } // set push/pull attributes to the remaining edges @@ -96,18 +140,57 @@ return graph; } - static private void trackEdges(Node resNode, List resNodes) { - // recursively set push only attributes to input side edges + static private void trackEdgesBackwardForPush(Node resNode, HashSet unvisitedNodes) { + // recursively turn push only backward in data-flow. for (Edge chToRes : ((ResourceNode) resNode).getInEdges()) { - Node chNode = chToRes.getSource(); - for (Edge resToCh : ((ChannelNode) chNode).getInEdges()) { + ChannelNode chNode = (ChannelNode) chToRes.getSource(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set inEdges = new HashSet<>(); + inEdges.addAll(chNode.getInEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + inEdges.addAll(ancestorCh.getInEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + inEdges.addAll(descendantCh.getInEdges()); + } + for (Edge resToCh: inEdges) { 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); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesBackwardForPush(resNode2, unvisitedNodes); + } + } + } + } + + private static void trackEdgesForwardForPull(Node resNode, HashSet unvisitedNodes) { + // recursively turn pull only forward in data-flow. + for (Edge resToCh : ((ResourceNode) resNode).getOutEdges()) { + PushPullAttribute ppat = new PushPullAttribute(); + ppat.addOption(PushPullValue.PULL); + ((DataFlowEdge) resToCh).setAttribute(ppat); + ChannelNode chNode = (ChannelNode) resToCh.getDestination(); + // Should take into account the channel hierarchy. + Set ancestorChannels = chNode.getAncestors(); + Set descendantChannels = chNode.getDescendants(); + Set outEdges = new HashSet<>(); + outEdges.addAll(chNode.getOutEdges()); + for (ChannelNode ancestorCh: ancestorChannels) { + outEdges.addAll(ancestorCh.getOutEdges()); + } + for (ChannelNode descendantCh: descendantChannels) { + outEdges.addAll(descendantCh.getOutEdges()); + } + for (Edge chToRes: outEdges) { + Node resNode2 = chToRes.getDestination(); + if (unvisitedNodes.contains(resNode2)) { + unvisitedNodes.remove(resNode2); + trackEdgesForwardForPull(resNode2, unvisitedNodes); } } }