namespace
| 114 | } |
| 115 | } // namespace |
| 116 | Status GraphCompiler::Compile() { |
| 117 | // Check that the graph has no illegal cycles. |
| 118 | TF_RETURN_IF_ERROR(graph::ValidateGraphHasNoCycle(*graph_)); |
| 119 | // Maintain a mapping from node id to node outputs. |
| 120 | using NodeOutputs = std::vector<TensorValue>; |
| 121 | std::vector<NodeOutputs> output_registry(graph_->num_node_ids()); |
| 122 | auto output_registry_cleanup = gtl::MakeCleanup([&output_registry] { |
| 123 | for (const NodeOutputs& outputs : output_registry) { |
| 124 | for (const TensorValue& value : outputs) { |
| 125 | CHECK(!value.is_ref()); |
| 126 | delete value.tensor; |
| 127 | } |
| 128 | } |
| 129 | }); |
| 130 | |
| 131 | // XLA requires determinism, generate a stable ordering from DFS. |
| 132 | std::vector<Node*> topo_sorted_nodes; |
| 133 | GetReversePostOrder(*graph_, &topo_sorted_nodes, |
| 134 | /*stable_comparator=*/NodeComparatorName()); |
| 135 | |
| 136 | OpKernelContext::Params params; |
| 137 | PartiallySetupParams(¶ms); |
| 138 | |
| 139 | for (Node* n : topo_sorted_nodes) { |
| 140 | OpKernel* op_kernel_raw = nullptr; |
| 141 | // The kernel is not actually run for functional ops, we just need it |
| 142 | // for metadata. |
| 143 | Status s = flib_->CreateKernel(n->def(), &op_kernel_raw); |
| 144 | // Transfer ownership of the kernel to a local smart pointer. |
| 145 | std::unique_ptr<OpKernel> op_kernel(op_kernel_raw); |
| 146 | |
| 147 | if (!s.ok()) { |
| 148 | s = AttachDef(s, *n); |
| 149 | LOG(ERROR) << "Executor failed to create kernel. " << s; |
| 150 | return s; |
| 151 | } |
| 152 | |
| 153 | TF_RET_CHECK(!n->IsRecv() && !n->IsSend() && !n->IsSwitch()) |
| 154 | << "Not supported node: " << n->DebugString(); |
| 155 | params.op_kernel = op_kernel.get(); |
| 156 | absl::InlinedVector<AllocatorAttributes, 4> output_attr(n->num_outputs()); |
| 157 | params.output_attr_array = output_attr.data(); |
| 158 | |
| 159 | // tensor_inputs_ is a buffer reused across graph traversal. We clean up and |
| 160 | // reinitialize the buffer before we visit a new node. |
| 161 | tensor_inputs_.clear(); |
| 162 | tensor_inputs_.resize(n->num_inputs()); |
| 163 | |
| 164 | // Set up inputs from outputs of previous nodes. |
| 165 | for (auto* e : n->in_edges()) { |
| 166 | if (e->IsControlEdge()) continue; |
| 167 | const Node* src = e->src(); |
| 168 | TF_RET_CHECK(src->id() < output_registry.size()); |
| 169 | const NodeOutputs& src_outputs = output_registry[src->id()]; |
| 170 | |
| 171 | tensor_inputs_.at(e->dst_input()) = src_outputs.at(e->src_output()); |
| 172 | } |
| 173 |
nothing calls this directly
no test coverage detected