10cf9ed3a719c0782695154d5a0bca260001cec15A. Unique TensorFlower/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
21c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
31c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerLicensed under the Apache License, Version 2.0 (the "License");
41c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFloweryou may not use this file except in compliance with the License.
51c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerYou may obtain a copy of the License at
61c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
71c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    http://www.apache.org/licenses/LICENSE-2.0
81c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
91c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerUnless required by applicable law or agreed to in writing, software
101c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerdistributed under the License is distributed on an "AS IS" BASIS,
111c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerSee the License for the specific language governing permissions and
131c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerlimitations under the License.
141c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower==============================================================================*/
151c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
161c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower#include "tensorflow/python/lib/core/py_func.h"
171c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
18edaf3b342db4afa1c872da541fb0ac176a4e8ef9A. Unique TensorFlower#include <array>
19edaf3b342db4afa1c872da541fb0ac176a4e8ef9A. Unique TensorFlower
201c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower#include "numpy/arrayobject.h"
21f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal#include "tensorflow/c/eager/c_api.h"
2287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal#include "tensorflow/c/eager/c_api_internal.h"
23f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal#include "tensorflow/c/tf_status_helper.h"
24e85d3df92deb9d717befdf173966a2913ac2aea0Geoffrey Irving#include "tensorflow/core/framework/allocation_description.pb.h"
251c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower#include "tensorflow/core/framework/op_kernel.h"
261c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower#include "tensorflow/core/lib/core/errors.h"
271c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower#include "tensorflow/core/lib/core/threadpool.h"
28252bb90ca2dd412ca2fd2908faf1a25d6ef618cfJosh Levenberg#include "tensorflow/core/platform/macros.h"
29ded61708dbc7f5615119a3623c8fe7f112882e0fJosh Levenberg#include "tensorflow/core/platform/mutex.h"
30b2f0bc2e230dcd690e7cf34e5425f0f499d9557bJosh Levenberg#include "tensorflow/core/platform/types.h"
31f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal#include "tensorflow/python/eager/pywrap_tfe.h"
32a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower#include "tensorflow/python/lib/core/ndarray_tensor_bridge.h"
337921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie#include "tensorflow/python/lib/core/py_util.h"
34f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal#include "tensorflow/python/lib/core/safe_ptr.h"
35d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie
36dc0427d4865f99a227f0c05e2c84987b5ad7f527A. Unique TensorFlower#include <Python.h>
371c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
381c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowernamespace tensorflow {
391c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowernamespace {
401c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
41f93c48dc061d23495a4425fcad17d55159cb02b1A. Unique TensorFlowerstatic mutex mu(LINKER_INITIALIZED);
421c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerstatic PyObject* py_trampoline GUARDED_BY(mu) = nullptr;
431c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
441c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// Returns the py_trampoline that is used to pass the control to the
451c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// python runtime.
461c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerPyObject* GetPyTrampoline() {
471c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  mutex_lock l(mu);
481c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  return py_trampoline;
491c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}
501c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
511c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// A call to the registered python function.
521c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerstruct PyCall {
531c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  // Passed to python runtime to call the python function registered
541c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  // with this "token".
551c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  string token;
561c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
5787a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  // The device on which Tensors are stored; only used for EagerPyFunc.
5887a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  Device* device;
5987a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal
6087a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  // True if and only if the op has been placed on a GPU.
6187a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  bool gpu;
6287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal
63f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  // True if the call is associated with an EagerPyFunc.
64f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  bool eager;
65f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal
66b1413783a47bbf94dfbdd6e31d0e4a765a966d41Benoit Steiner  // Inputs and outputs of this function invocation.
671c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  std::vector<Tensor> ins;
681c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  std::vector<Tensor> out;
691c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower};
701c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
711c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// Givens the 'call', prepares the token and inputs as a python tuple
721c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// that is appropriate for calling the trampoline.
73f37380b064948fb6dd45feef0e8d93130c2f9884Akshay AgrawalStatus MakeArgTuple(const PyCall* call, PyObject** tuple) {
741c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  int64 n = call->ins.size();
751c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  PyObject* lst = PyList_New(n);
761c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  CHECK(lst);
771c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  for (int64 i = 0; i < n; ++i) {
78f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    PyObject* arg = nullptr;
791c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    const Tensor& t = call->ins[i];
80f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    if (call->eager) {
8187a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      if (call->gpu) {
8287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        arg = EagerTensorFromHandle(new TFE_TensorHandle(t, call->device));
8387a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      } else {
8487a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        // TFE_TensorHandle assumes that CPU is identified by `nullptr`.
8587a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        arg = EagerTensorFromHandle(new TFE_TensorHandle(t, nullptr));
8687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      }
87f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      if (arg == nullptr) {
88f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal        return errors::Internal("Unable to procure EagerTensor from Tensor.");
89f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      }
90f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    } else {
91f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      Status s = ConvertTensorToNdarray(t, &arg);
92f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      if (!s.ok()) {
93f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal        Py_DECREF(lst);
94f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal        return s;
95f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      }
961c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    }
97f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    PyList_SetItem(lst, i, arg);
981c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
9987a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  *tuple = Py_BuildValue("(sON)", call->token.c_str(),
10087a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal                         call->gpu ? Py_True : Py_False, lst);
1011c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  CHECK(*tuple);
1021c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  return Status::OK();
1031c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}
1041c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
105a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower// Returns the corresponding tf dtype in 'tf' for numpy data type
106a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower// 'np'.  Returns an error if the type is not supported by this
107a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower// module.
108a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlowerStatus NumericNpDTypeToTfDType(const int np, DataType* tf) {
109a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  switch (np) {
110a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_FLOAT16:
111a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_HALF;
112a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
113a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_FLOAT32:
114a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_FLOAT;
115a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
116a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_FLOAT64:
117a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_DOUBLE;
118a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
119a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_INT32:
120a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_INT32;
121a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
122a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_UINT8:
123a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_UINT8;
124a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
125a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_INT8:
126a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_INT8;
127a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
128a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_INT16:
129a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_INT16;
130a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
131a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_INT64:
132a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_INT64;
133a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
134a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_BOOL:
135a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_BOOL;
136a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
137a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_COMPLEX64:
138a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_COMPLEX64;
139a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
140a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_COMPLEX128:
141a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *tf = DT_COMPLEX128;
142a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
143a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    default:
144a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      return errors::Unimplemented("Unsupported numpy type ", np);
145a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
146a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  return Status::OK();
147a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower}
148a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
149cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlowerbool IsSingleNone(PyObject* obj) {
150cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  if (!PyArray_Check(obj)) {
151cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower    return false;
152cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  }
153cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  PyArrayObject* array_obj = reinterpret_cast<PyArrayObject*>(obj);
154cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  if (PyArray_NDIM(array_obj) != 0 || PyArray_SIZE(array_obj) != 1) {
155cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower    return false;
156cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  }
157edaf3b342db4afa1c872da541fb0ac176a4e8ef9A. Unique TensorFlower  std::array<npy_intp, 0> indices;
158d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie  char* item_ptr =
159d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie      static_cast<char*>(PyArray_GetPtr(array_obj, indices.data()));
160cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  PyObject* item = PyArray_GETITEM(array_obj, item_ptr);
161cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  CHECK(item);
162cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower  return item == Py_None;
163cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower}
164cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower
165f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal// Retrieves a Tensor from `eager_tensor` and stores it in `output_tensor`.
16687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawalvoid ExtractTensorFromEagerTensor(const PyObject* eager_tensor,
16787a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal                                  Tensor* output_tensor) {
16887a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  *output_tensor = EagerTensor_Handle(eager_tensor)->t;
169f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal}
170f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal
1711c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower// Calls the registered py function through the trampoline.
172c154d4719eea88e694f4c06bcb1249dbac0f7877Derek MurrayStatus DoCallPyFunc(PyCall* call, bool* out_log_on_error) {
173c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray  *out_log_on_error = true;
1741c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  PyObject* trampoline = GetPyTrampoline();
1751c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  if (trampoline == nullptr) {
1761c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    return errors::InvalidArgument(
1771c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower        "Missing py trampoline. Most likely, it is a link error.");
1781c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
1791c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  // Prepare the argument.
1801c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  PyObject* args = nullptr;
1811c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  TF_RETURN_IF_ERROR(MakeArgTuple(call, &args));
1821c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  CHECK(args);
1831c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
1841c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  // Invokes the trampoline.
1851c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  PyObject* result = PyEval_CallObject(trampoline, args);
1861c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  Py_DECREF(args);
1871c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  if (result == nullptr) {
188bf20a3a53296c0cc4a2c03e2d0b9a81703b7e8d6A. Unique TensorFlower    if (PyErr_Occurred()) {
189d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      if (PyErr_ExceptionMatches(PyExc_ValueError) ||
190d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo          PyErr_ExceptionMatches(PyExc_TypeError)) {
1917921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie        return errors::InvalidArgument(PyExceptionFetch());
192d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      } else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
193c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray        *out_log_on_error = false;
1947921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie        return errors::OutOfRange(PyExceptionFetch());
195d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      } else if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
1967921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie        return errors::ResourceExhausted(PyExceptionFetch());
197d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      } else if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
1987921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie        return errors::Unimplemented(PyExceptionFetch());
199d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      } else {
200d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo        // TODO(ebrevdo): Check if exception is an OpError and use the
201d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo        // OpError.error_code property to map it back in the Status.
2027921d01ec8fed3e5c62264b99b09440ea09796feAllen Lavoie        return errors::Unknown(PyExceptionFetch());
203d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      }
204d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo    } else {
205d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo      return errors::Internal("Failed to run py callback ", call->token,
206d1026cf28991318c4551e691aa03927eaf4ff157Eugene Brevdo                              ": see error log.");
207bf20a3a53296c0cc4a2c03e2d0b9a81703b7e8d6A. Unique TensorFlower    }
2081c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
2091c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
210f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  // Process the return values and convert them to TF Tensors.
21187a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  Status s = Status::OK();
2121c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  if (PyList_Check(result)) {
21387a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    // `result` is a Python list; if this operation is an `EagerPyFunc`, then
21487a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    // every item in the list must be an `EagerTensor`; otherwise, every element
21587a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    // must be a NumPy array.
2161c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    call->out.clear();
2171c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    for (int i = 0; i < PyList_Size(result); ++i) {
2181c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower      Tensor t;
219f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      if (call->eager) {
22087a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        const PyObject* item = PyList_GetItem(result, i);
22187a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        if (EagerTensor_CheckExact(item)) {
22287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal          ExtractTensorFromEagerTensor(item, &t);
22387a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        } else {
22487a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal          s = errors::FailedPrecondition(
22587a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal              "Expected EagerTensor, found PyObject of type: ",
22687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal              Py_TYPE(item)->tp_name);
22787a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        }
228f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      } else {
229f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal        s = ConvertNdarrayToTensor(PyList_GetItem(result, i), &t);
230f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal      }
231f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal
2321c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower      if (!s.ok()) {
2331c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower        break;
2341c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower      }
2351c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower      call->out.push_back(t);
2361c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    }
237f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  } else if (EagerTensor_CheckExact(result) || result == Py_None) {
23887a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    // result is an `EagerTensor` or `None`.
239f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    DCHECK(call->eager);
240f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    Tensor t;
241f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    if (result != Py_None) {
24287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      ExtractTensorFromEagerTensor(result, &t);
24387a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      call->out.push_back(t);
244f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    }
2451c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  } else if (PyArray_Check(result)) {
24687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    // `result` is a NumPy array.
247f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    DCHECK(!call->eager);
248cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower    if (!IsSingleNone(result)) {
249cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower      Tensor t;
250cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower      s = ConvertNdarrayToTensor(result, &t);
251cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower      if (s.ok()) {
252cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower        call->out.push_back(t);
253cabaef0f964c3639f6fe20dd218b1d692b7d632eA. Unique TensorFlower      }
2541c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    }
2551c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  } else {
25687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    s = errors::Internal("Unexpected PyObject was returned: ",
2572b3395a7a997f229e19b8b3fb75bd9d1430ca2fbA. Unique TensorFlower                         Py_TYPE(result)->tp_name);
2581c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
2591c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  Py_DECREF(result);
2601c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  return s;
2611c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}
2621c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
2631c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}  // end namespace
2641c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
265a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower// Outside anonymous namespace just to make the friend declaration in
266a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower// tensorflow::Tensor apply.
267a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlowerclass NumpyTensorBuffer : public TensorBuffer {
268a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower public:
269a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  NumpyTensorBuffer(PyArrayObject* array, size_t len, void* data)
270a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      : array_(array), len_(len), data_(data) {}
271a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
272a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  ~NumpyTensorBuffer() override {
273a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    // Note: The session::run wrapper is responsible for freeing this while
274a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    // holding the GIL.
275a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    DelayedNumpyDecref(data_, len_, array_);
276a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
277a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
278a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  void* data() const override { return data_; }
279a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  size_t size() const override { return len_; }
280a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  TensorBuffer* root_buffer() override { return this; }
281a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  void FillAllocationDescription(AllocationDescription* proto) const override {
282a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    tensorflow::int64 rb = size();
283a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    proto->set_requested_bytes(rb);
284a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    proto->set_allocator_name(tensorflow::cpu_allocator()->Name());
285a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
286a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  Tensor MakeTensor(DataType dtype, const TensorShape& shape) {
287a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    CHECK_EQ(len_, shape.num_elements() * DataTypeSize(dtype));
288a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    return Tensor(dtype, shape, this);
289a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
290a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
291a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  // Prevents input forwarding from overwriting this buffer.
292a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  bool OwnsMemory() const override { return false; }
293a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
294a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower private:
295a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  PyArrayObject* array_;
296a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  size_t len_;
297a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  void* data_;
298a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower};
2994c85b12dfffe371e6a75e39dd08573c88f960558Alexandre Passos
3007e538db04d9ecf2432f8f0c7bf2d6d5c1f994e1aA. Unique TensorFlowerStatus ConvertNdarrayToTensor(PyObject* obj, Tensor* ret) {
301a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  PyArrayObject* input = reinterpret_cast<PyArrayObject*>(obj);
302a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  DataType dtype = DT_INVALID;
303a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  TensorShape shape;
304a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  for (int i = 0; i < PyArray_NDIM(input); ++i) {
305a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    shape.AddDim(PyArray_SHAPE(input)[i]);
306a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
307a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  const int np_type = PyArray_TYPE(input);
308a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  switch (np_type) {
309a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_OBJECT: {
310a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      dtype = DT_STRING;
311a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      Tensor t(dtype, shape);
312a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      auto tflat = t.flat<string>();
313a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      PyObject** input_data = reinterpret_cast<PyObject**>(PyArray_DATA(input));
314a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      for (int i = 0; i < tflat.dimension(0); ++i) {
315a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        char* el;
316a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        Py_ssize_t el_size;
317a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        if (PyBytes_AsStringAndSize(input_data[i], &el, &el_size) == -1) {
31817ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray#if PY_MAJOR_VERSION >= 3
31917ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray          el = PyUnicode_AsUTF8AndSize(input_data[i], &el_size);
320d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie#else
321d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie          el = nullptr;
322d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie          if (PyUnicode_Check(input_data[i])) {
323d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie            PyObject* unicode = PyUnicode_AsUTF8String(input_data[i]);
324d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie            if (unicode) {
325d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie              if (PyString_AsStringAndSize(unicode, &el, &el_size) == -1) {
326d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie                Py_DECREF(unicode);
327d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie                el = nullptr;
328d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie              }
329d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie            }
330d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie          }
33117ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray#endif
332d9f93c42a50b1f1401d9c186eac0ae8dc9093c3bJianwei Xie          if (!el) {
33317ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray            return errors::Unimplemented("Unsupported object type ",
33417ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray                                         input_data[i]->ob_type->tp_name);
33517ba3a69f4c3509711a3da5eff3cb6be99e0936dDerek Murray          }
336a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        }
337a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        tflat(i) = string(el, el_size);
338a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      }
339a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *ret = t;
340a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
341a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    }
342a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    case NPY_STRING: {
343a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      dtype = DT_STRING;
344a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      Tensor t(dtype, shape);
345a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      auto tflat = t.flat<string>();
346a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      char* input_data = PyArray_BYTES(input);
347a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      Py_ssize_t el_size = PyArray_ITEMSIZE(input);
348a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      for (int i = 0; i < tflat.dimension(0); ++i) {
349a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        tflat(i) = string(input_data + i * el_size, el_size);
350a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      }
351a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      *ret = t;
352a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      break;
353a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    }
354a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    default: {
355a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      TF_RETURN_IF_ERROR(NumericNpDTypeToTfDType(PyArray_TYPE(input), &dtype));
356a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      CHECK(DataTypeCanUseMemcpy(dtype));
357a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      if (reinterpret_cast<intptr_t>(PyArray_DATA(input)) %
358a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower              EIGEN_MAX_ALIGN_BYTES !=
359a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower          0) {
360a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        Tensor t(dtype, shape);
361a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        StringPiece p = t.tensor_data();
362a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        memcpy(const_cast<char*>(p.data()), PyArray_DATA(input), p.size());
363a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        *ret = t;
364a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      } else {
365a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        // Incref the array as the calling context will decref it when we
366a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        // return and we want to keep a handle to this memory.
367a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        Py_INCREF(input);
368a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        NumpyTensorBuffer* buf = new NumpyTensorBuffer(
369a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower            input, shape.num_elements() * DataTypeSize(dtype),
370a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower            PyArray_DATA(input));
371a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        *ret = buf->MakeTensor(dtype, shape);
372a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        buf->Unref();
373a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      }
374a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    }
3757e538db04d9ecf2432f8f0c7bf2d6d5c1f994e1aA. Unique TensorFlower  }
376a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  return Status::OK();
3777e538db04d9ecf2432f8f0c7bf2d6d5c1f994e1aA. Unique TensorFlower}
3787e538db04d9ecf2432f8f0c7bf2d6d5c1f994e1aA. Unique TensorFlower
379a5a8558feb9417359e30a991ab5e01cf17194473Alexandre Passos// Creates a numpy array in 'ret' which either aliases the content of 't' or has
380a5a8558feb9417359e30a991ab5e01cf17194473Alexandre Passos// a copy.
3818baea485d6c3fafff8fd2d14cb0367318efcbd14Sherry MooreStatus ConvertTensorToNdarray(const Tensor& t, PyObject** ret) {
382a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  int typenum = -1;
383a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  TF_RETURN_IF_ERROR(TF_DataType_to_PyArray_TYPE(
384a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      static_cast<TF_DataType>(t.dtype()), &typenum));
385a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  PyArray_Descr* descr = PyArray_DescrFromType(typenum);
386a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  CHECK(descr);
387a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  std::vector<npy_intp> dims;
388a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  dims.reserve(t.dims());
389a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  for (int i = 0; i < t.dims(); ++i) {
390a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    dims.push_back(t.dim_size(i));
391a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
392a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  Tensor* copy = new Tensor(t);
393a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  if (ArrayFromMemory(dims.size(), dims.data(),
394a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower                      const_cast<char*>(copy->tensor_data().data()), t.dtype(),
395a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower                      [copy]() { delete copy; }, ret)
396a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower          .ok()) {
397a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    return Status::OK();
398a5a8558feb9417359e30a991ab5e01cf17194473Alexandre Passos  }
399a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  delete copy;
400a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower
401a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  PyObject* obj = PyArray_Empty(dims.size(), dims.data(), descr, 0);
402a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  if (obj == nullptr) {
403a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    return errors::Internal("Failed to allocate np array: ",
404a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower                            t.shape().DebugString());
405a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
406a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  PyArrayObject* np_array = reinterpret_cast<PyArrayObject*>(obj);
407a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  if (typenum == NPY_OBJECT) {
408a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    CHECK_EQ(DT_STRING, t.dtype());
409a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    auto tflat = t.flat<string>();
410a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    PyObject** out = reinterpret_cast<PyObject**>(PyArray_DATA(np_array));
411a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    for (int i = 0; i < tflat.dimension(0); ++i) {
412a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      const string& el = tflat(i);
413a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      out[i] = PyBytes_FromStringAndSize(el.data(), el.size());
414a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      if (out[i] == nullptr) {
415a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        for (int j = 0; j < i; ++j) {
416a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower          Py_DECREF(out[j]);
417a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        }
418a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        Py_DECREF(obj);
419a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower        return errors::Internal("Failed to allocate a copy of string ", i);
420a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower      }
421a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    }
422a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  } else {
423a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    CHECK(DataTypeCanUseMemcpy(t.dtype()));
424a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    StringPiece p = t.tensor_data();
425a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower    memcpy(PyArray_DATA(np_array), p.data(), p.size());
426a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  }
427a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  *ret = PyArray_Return(np_array);
428a2182c4a3d0f6dc29042cd6116964a3f5241b5b0A. Unique TensorFlower  return Status::OK();
4298baea485d6c3fafff8fd2d14cb0367318efcbd14Sherry Moore}
4308baea485d6c3fafff8fd2d14cb0367318efcbd14Sherry Moore
4311c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowervoid InitializePyTrampoline(PyObject* trampoline) {
4321c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  mutex_lock l(mu);
4331c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  if (py_trampoline == nullptr) {
4341c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    py_trampoline = trampoline;
4351c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    Py_INCREF(py_trampoline);
4361c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  } else {
4371c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    LOG(WARNING) << "InitializeCallback should only be called once";
4381c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
4391c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}
4401c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
441f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlowerclass PyFuncOp : public OpKernel {
4421c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower public:
443f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower  explicit PyFuncOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
4441c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    OP_REQUIRES_OK(ctx, ctx->GetAttr("token", &token_));
445f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    eager_ = type_string() == "EagerPyFunc";
44687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    gpu_ = ctx->device_type().type_string() == DEVICE_GPU;
4471c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
4481c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
449f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower  void Compute(OpKernelContext* ctx) override {
450f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    PyCall call;
451f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    call.token = token_;
45287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    call.gpu = gpu_;
453f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal    call.eager = eager_;
45487a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    if (call.eager) {
45587a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      // Eager's C API uses `Device`, whereas `OpKernelContext` stores a
45687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      // `DeviceBase`; attempt to downcast.
45787a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      call.device = dynamic_cast<Device*>(ctx->device());
45887a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      if (call.device == nullptr) {
45987a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal        ctx->CtxFailureWithWarning(
46087a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal            errors::Internal("Unrecognized device class"));
46187a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal      }
46287a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal    }
46387a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal
4641c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    for (int i = 0; i < ctx->num_inputs(); ++i) {
465f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower      call.ins.push_back(ctx->input(i));
466f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    }
467f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower
468f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    PyGILState_STATE py_threadstate;
469f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    py_threadstate = PyGILState_Ensure();
470c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray    bool log_on_error;
471c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray    Status s = DoCallPyFunc(&call, &log_on_error);
472e4532d20973c4c00854492362665317551661c18A. Unique TensorFlower    // Sometimes py_funcs can be called without a session and leak memory. This
473e4532d20973c4c00854492362665317551661c18A. Unique TensorFlower    // ensures we clear the decref cache so this doesn't happen.
474e4532d20973c4c00854492362665317551661c18A. Unique TensorFlower    ClearDecrefCache();
475f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    PyGILState_Release(py_threadstate);
476f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower
477f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    // Ensures that GIL is released even when !s.ok().
478c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray    if (!s.ok()) {
479c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray      if (log_on_error) {
480c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray        ctx->CtxFailureWithWarning(s);
481c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray      } else {
482c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray        ctx->CtxFailure(s);
483c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray      }
484c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray      return;
485c154d4719eea88e694f4c06bcb1249dbac0f7877Derek Murray    }
486f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower
487f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    OP_REQUIRES(ctx, static_cast<int32>(call.out.size()) == ctx->num_outputs(),
488f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower                errors::InvalidArgument(token_, " returns ", call.out.size(),
489f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower                                        " values, but expects to see ",
490f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower                                        ctx->num_outputs(), " values."));
491f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower    for (size_t i = 0; i < call.out.size(); ++i) {
492f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower      const auto& t = call.out[i];
493f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower      OP_REQUIRES(
494f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower          ctx, t.dtype() == output_type(i),
495f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower          errors::InvalidArgument(i, "-th value returned by ", token_, " is ",
496f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower                                  DataTypeString(t.dtype()), ", but expects ",
497f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower                                  DataTypeString(output_type(i))));
498f139c2b3f1298fe63afb31f7956f0e27cf7935f6A. Unique TensorFlower      ctx->set_output(i, t);
4991c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower    }
5001c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  }
5011c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
5021c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower private:
5031c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  string token_;
5041c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
50587a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  // True if and only if this op has been placed on a GPU.
50687a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal  bool gpu_;
50787a3c967973641d3b0d2a16d17add184ed967392Akshay Agrawal
508f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  // True if and only if this op should execute the python function eagerly,
509f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  // i.e., if and only if the eager attribute is set.
510f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal  bool eager_;
511f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal
5121c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower  TF_DISALLOW_COPY_AND_ASSIGN(PyFuncOp);
5131c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower};
514f37380b064948fb6dd45feef0e8d93130c2f9884Akshay Agrawal
5151c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlowerREGISTER_KERNEL_BUILDER(Name("PyFunc").Device(DEVICE_CPU), PyFuncOp);
5162c5b766688d7217886d76b05989475d86869ca21A. Unique TensorFlowerREGISTER_KERNEL_BUILDER(Name("PyFuncStateless").Device(DEVICE_CPU), PyFuncOp);
517f37380b064948fb6dd45feef0e8d93130c2f9884Akshay AgrawalREGISTER_KERNEL_BUILDER(Name("EagerPyFunc").Device(DEVICE_CPU), PyFuncOp);
51887a3c967973641d3b0d2a16d17add184ed967392Akshay AgrawalREGISTER_KERNEL_BUILDER(Name("EagerPyFunc").Device(DEVICE_GPU), PyFuncOp);
5191c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower
5201c579361cd1e088dd5e05a394b1561a73e3667baA. Unique TensorFlower}  // end namespace tensorflow
521