Constructs a control loop. Returns a struct containing the newly created enter, merge, and switch nodes. The enter and merge nodes are used in the recursive construction of control loops for nested frames (loops). The switch node will be connected to the LoopCond node. The merge node will be connected to all the recvs of the same frame by control edges when the actual partitioning happens.
| 706 | // be connected to all the recvs of the same frame by control edges when |
| 707 | // the actual partitioning happens. |
| 708 | Status AddControlLoop(const PartitionOptions& opts, Graph* g, const Node* src, |
| 709 | const Edge* edge, Node* loop_cond, |
| 710 | std::vector<ControlFlowInfo>* cf_info, |
| 711 | ControlLoop* loop) { |
| 712 | Status status; |
| 713 | GraphDefBuilder::Options bopts(g, &status); |
| 714 | const ControlFlowInfo& src_info = (*cf_info)[src->id()]; |
| 715 | const string& device_name = edge->dst()->assigned_device_name(); |
| 716 | const string& frame_name = src_info.frame_name; |
| 717 | int parallel_iterations; |
| 718 | status = GetNodeAttr(src_info.frame->attrs(), "parallel_iterations", |
| 719 | ¶llel_iterations); |
| 720 | if (!status.ok()) return status; |
| 721 | |
| 722 | // The names of the nodes to be added. |
| 723 | const string& enter_name = |
| 724 | ControlLoopName(opts.new_name(edge->dst()->name())); |
| 725 | const string& merge_name = |
| 726 | ControlLoopName(opts.new_name(edge->dst()->name())); |
| 727 | const string& switch_name = |
| 728 | ControlLoopName(opts.new_name(edge->dst()->name())); |
| 729 | const string& next_name = ControlLoopName(opts.new_name(edge->dst()->name())); |
| 730 | |
| 731 | // Add the nodes to the graph g. |
| 732 | Node* enter = AddControlEnter(g, enter_name, device_name, frame_name, |
| 733 | parallel_iterations, &status); |
| 734 | if (!status.ok()) return status; |
| 735 | Node* merge = AddControlMerge(enter_name, next_name, g, merge_name, |
| 736 | device_name, &status); |
| 737 | if (!status.ok()) return status; |
| 738 | Node* switch_node = AddControlSwitch(merge, loop_cond, device_name, |
| 739 | bopts.WithName(switch_name)); |
| 740 | if (!status.ok()) return status; |
| 741 | Node* next = |
| 742 | AddControlNext({switch_node, 1}, device_name, bopts.WithName(next_name)); |
| 743 | if (!status.ok()) return status; |
| 744 | |
| 745 | // Add control flow info for these new nodes: |
| 746 | AddControlFlowInfo(enter, src, cf_info); |
| 747 | AddControlFlowInfo(merge, src, cf_info); |
| 748 | AddControlFlowInfo(switch_node, src, cf_info); |
| 749 | AddControlFlowInfo(next, src, cf_info); |
| 750 | |
| 751 | // Add input edges for the newly created merge node: |
| 752 | g->AddEdge(enter, 0, merge, 0); |
| 753 | g->AddEdge(next, 0, merge, 1); |
| 754 | |
| 755 | loop->enter = enter; |
| 756 | loop->merge = merge; |
| 757 | loop->switch_node = switch_node; |
| 758 | return Status::OK(); |
| 759 | } |
| 760 | |
| 761 | const Node* InputFrame(const Node* node, |
| 762 | const std::vector<ControlFlowInfo>& cf_info) { |
no test coverage detected