TODO(gjn): Consider moving into ExecuteNode class
| 944 | |
| 945 | // TODO(gjn): Consider moving into ExecuteNode class |
| 946 | Status EagerKernelExecute(EagerContext* ctx, |
| 947 | const gtl::InlinedVector<TensorHandle*, 4>& op_inputs, |
| 948 | const core::RefCountPtr<KernelAndDevice>& kernel, |
| 949 | NodeExecStats* maybe_stats, |
| 950 | StepStats* maybe_step_stats, |
| 951 | GraphCollector* graph_collector, |
| 952 | CancellationManager* cancellation_manager, |
| 953 | absl::Span<TensorHandle*> retvals) { |
| 954 | profiler::TraceMe activity("EagerKernelExecute", |
| 955 | profiler::TraceMeLevel::kInfo); |
| 956 | std::vector<Tensor> outputs(1); |
| 957 | |
| 958 | // If there are multiple references to a TensorHandle in 'op_inputs' we must |
| 959 | // increment the reference count of the corresponding Tensor or risk it being |
| 960 | // overwritten during kernel execution. The reference count is incremented |
| 961 | // below when we insert a copy of the Tensor into protected_tensors, and will |
| 962 | // be decremented once execution is complete. |
| 963 | std::vector<tensorflow::Tensor> protected_tensors; |
| 964 | for (int i = 0; i < op_inputs.size(); ++i) { |
| 965 | if (!op_inputs[i]->RefCountIsOne()) { |
| 966 | const Tensor* input_tensor = nullptr; |
| 967 | TF_RETURN_IF_ERROR(op_inputs[i]->Tensor(&input_tensor)); |
| 968 | protected_tensors.push_back(*input_tensor); |
| 969 | } |
| 970 | } |
| 971 | |
| 972 | gtl::InlinedVector<TensorValue, 4> input_vector(op_inputs.size()); |
| 973 | for (int i = 0; i < op_inputs.size(); ++i) { |
| 974 | TF_RETURN_IF_ERROR(op_inputs[i]->TensorValue(&input_vector[i])); |
| 975 | } |
| 976 | |
| 977 | // TODO(apassos) figure out how to record stats for ops which are a part of |
| 978 | // functions. |
| 979 | // TODO(agarwal): change Run to take vector of handles ? |
| 980 | // TODO(b/111859745): When we support recovering from kernel/device errors, we |
| 981 | // would need to call XlaDevice::EnsureDeviceContextOk() before using an XLA |
| 982 | // device. We don't call it now because it is an unneeded overhead (it |
| 983 | // acquires a lock) and we can't recover from errors anyway. |
| 984 | ScopedStepContainer* container = ctx->StepContainer(); |
| 985 | if (container == nullptr) { |
| 986 | TF_RETURN_IF_ERROR(kernel->Run(input_vector, &outputs, maybe_stats, |
| 987 | maybe_step_stats, graph_collector, |
| 988 | cancellation_manager)); |
| 989 | } else { |
| 990 | TF_RETURN_IF_ERROR(kernel->Run(container, input_vector, &outputs, |
| 991 | maybe_stats, maybe_step_stats, |
| 992 | graph_collector, cancellation_manager)); |
| 993 | } |
| 994 | if (graph_collector != nullptr) { |
| 995 | mutex_lock ml(*ctx->MetadataMu()); |
| 996 | { |
| 997 | GraphCollector* collector = ctx->GetGraphCollector(); |
| 998 | mutex_lock mll(collector->mu); |
| 999 | |
| 1000 | // Adding to partition graphs for backward compatibility. |
| 1001 | for (const auto& graph : collector->partitioned_graphs) { |
| 1002 | *ctx->RunMetadataProto()->add_partition_graphs() = graph; |
| 1003 | } |
no test coverage detected