| 2625 | } |
| 2626 | |
| 2627 | bool ReadVariableOp(const FastPathOpExecInfo& parent_op_exec_info, |
| 2628 | PyObject* input, tensorflow::Safe_PyObjectPtr* output, |
| 2629 | TF_Status* status) { |
| 2630 | MaybeNotifyVariableAccessed(input); |
| 2631 | |
| 2632 | TFE_Op* op = TFE_NewOp(parent_op_exec_info.ctx, "ReadVariableOp", status); |
| 2633 | auto cleaner = tensorflow::gtl::MakeCleanup([op] { TFE_DeleteOp(op); }); |
| 2634 | if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) return false; |
| 2635 | |
| 2636 | // Set dtype |
| 2637 | DCHECK(PyObject_HasAttrString(input, "_dtype")); |
| 2638 | tensorflow::Safe_PyObjectPtr dtype(PyObject_GetAttrString(input, "_dtype")); |
| 2639 | int value; |
| 2640 | if (!ParseTypeValue("_dtype", dtype.get(), status, &value)) { |
| 2641 | return false; |
| 2642 | } |
| 2643 | TFE_OpSetAttrType(op, "dtype", static_cast<TF_DataType>(value)); |
| 2644 | |
| 2645 | TFE_OpSetDevice(op, parent_op_exec_info.device_name, status); |
| 2646 | if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) return false; |
| 2647 | |
| 2648 | // Get handle |
| 2649 | tensorflow::Safe_PyObjectPtr handle(PyObject_GetAttrString(input, "_handle")); |
| 2650 | if (!EagerTensor_CheckExact(handle.get())) return false; |
| 2651 | TFE_OpAddInput(op, EagerTensor_Handle(handle.get()), status); |
| 2652 | if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) return false; |
| 2653 | |
| 2654 | int num_retvals = 1; |
| 2655 | TFE_TensorHandle* output_handle; |
| 2656 | TFE_Execute(op, &output_handle, &num_retvals, status); |
| 2657 | if (MaybeRaiseExceptionFromTFStatus(status, nullptr)) return false; |
| 2658 | |
| 2659 | // Always create the py object (and correctly DECREF it) from the returned |
| 2660 | // value, else the data will leak. |
| 2661 | output->reset(EagerTensorFromHandle(output_handle)); |
| 2662 | |
| 2663 | // TODO(nareshmodi): Should we run post exec callbacks here? |
| 2664 | if (parent_op_exec_info.run_gradient_callback) { |
| 2665 | tensorflow::Safe_PyObjectPtr inputs(PyTuple_New(1)); |
| 2666 | PyTuple_SET_ITEM(inputs.get(), 0, handle.release()); |
| 2667 | |
| 2668 | tensorflow::Safe_PyObjectPtr outputs(PyTuple_New(1)); |
| 2669 | Py_INCREF(output->get()); // stay alive after since tuple steals. |
| 2670 | PyTuple_SET_ITEM(outputs.get(), 0, output->get()); |
| 2671 | |
| 2672 | tensorflow::Safe_PyObjectPtr op_string( |
| 2673 | GetPythonObjectFromString("ReadVariableOp")); |
| 2674 | if (!RecordGradient(op_string.get(), inputs.get(), Py_None, outputs.get(), |
| 2675 | Py_None)) { |
| 2676 | return false; |
| 2677 | } |
| 2678 | } |
| 2679 | |
| 2680 | return true; |
| 2681 | } |
| 2682 | |
| 2683 | // Supports 3 cases at the moment: |
| 2684 | // i) input is an EagerTensor. |
no test coverage detected