1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #ifndef TENSORFLOW_C_EAGER_C_API_H_ 17 #define TENSORFLOW_C_EAGER_C_API_H_ 18 19 // C API extensions to experiment with eager execution of kernels. 20 // WARNING: Unlike tensorflow/c/c_api.h, the API here is not guaranteed to be 21 // stable and can change without notice. 22 23 #include "tensorflow/c/c_api.h" 24 25 // Macro to control visibility of exported symbols in the shared library (.so, 26 // .dylib, .dll). 27 // This duplicates the TF_EXPORT macro definition in 28 // tensorflow/core/platform/macros.h in order to keep this .h file independent 29 // of any other includes.$a 30 #ifdef SWIG 31 #define TF_CAPI_EXPORT 32 #else 33 #if defined(_WIN32) 34 #ifdef TF_COMPILE_LIBRARY 35 #define TF_CAPI_EXPORT __declspec(dllexport) 36 #else 37 #define TF_CAPI_EXPORT __declspec(dllimport) 38 #endif // TF_COMPILE_LIBRARY 39 #else 40 #define TF_CAPI_EXPORT __attribute__((visibility("default"))) 41 #endif // _WIN32 42 #endif // SWIG 43 44 #ifdef __cplusplus 45 extern "C" { 46 #endif 47 48 typedef struct TFE_ContextOptions TFE_ContextOptions; 49 50 // Return a new options object. 51 TF_CAPI_EXPORT extern TFE_ContextOptions* TFE_NewContextOptions(void); 52 53 // Set the config in TF_ContextOptions.options. 54 // config should be a serialized tensorflow.ConfigProto proto. 55 // If config was not parsed successfully as a ConfigProto, record the 56 // error information in *status. 57 TF_CAPI_EXPORT extern void TFE_ContextOptionsSetConfig( 58 TFE_ContextOptions* options, const void* proto, size_t proto_len, 59 TF_Status* status); 60 61 // Controls how to act when we try to run an operation on a given device but 62 // some input tensors are not on that device. 63 // LINT.IfChange 64 // Note: Keep in sync with internal copy of enum in eager/context.h. 65 typedef enum TFE_ContextDevicePlacementPolicy { 66 // Running operations with input tensors on the wrong device will fail. 67 TFE_DEVICE_PLACEMENT_EXPLICIT = 0, 68 // Copy the tensor to the right device but log a warning. 69 TFE_DEVICE_PLACEMENT_WARN = 1, 70 // Silently copy the tensor, which has a performance cost since the operation 71 // will be blocked till the copy completes. This is the default placement 72 // policy. 73 TFE_DEVICE_PLACEMENT_SILENT = 2, 74 // Placement policy which silently copies int32 tensors but not other dtypes. 75 TFE_DEVICE_PLACEMENT_SILENT_FOR_INT32 = 3, 76 } TFE_ContextDevicePlacementPolicy; 77 // LINT.ThenChange(//tensorflow/core/common_runtime/eager/context.h) 78 79 // Sets the default execution mode (sync/async). Note that this can be 80 // overridden per thread using TFE_ContextSetExecutorForThread. 81 TF_CAPI_EXPORT extern void TFE_ContextOptionsSetAsync(TFE_ContextOptions*, 82 unsigned char enable); 83 84 TF_CAPI_EXPORT extern void TFE_ContextOptionsSetDevicePlacementPolicy( 85 TFE_ContextOptions*, TFE_ContextDevicePlacementPolicy); 86 87 // Destroy an options object. 88 TF_CAPI_EXPORT extern void TFE_DeleteContextOptions(TFE_ContextOptions*); 89 90 // "Context" under which operations/functions are executed. It encapsulates 91 // things like the available devices, resource manager etc. 92 // TFE_Context must outlive all tensor handles created using it. In other 93 // words, TFE_DeleteContext() must be called after all tensor handles have 94 // been deleted (with TFE_DeleteTensorHandle). 95 // 96 // TODO(ashankar): Merge with TF_Session? 97 typedef struct TFE_Context TFE_Context; 98 99 TF_CAPI_EXPORT extern TFE_Context* TFE_NewContext( 100 const TFE_ContextOptions* opts, TF_Status* status); 101 TF_CAPI_EXPORT extern void TFE_DeleteContext(TFE_Context* ctx); 102 TF_CAPI_EXPORT extern TF_DeviceList* TFE_ContextListDevices(TFE_Context* ctx, 103 TF_Status* status); 104 105 // Clears the internal caches in the TFE context. Useful when reseeding random 106 // ops. 107 TF_CAPI_EXPORT extern void TFE_ContextClearCaches(TFE_Context* ctx); 108 109 // Sets a thread-local device placement policy. After this call, other calls to 110 // TFE_Execute in the same thread will use the device policy specified here 111 // instead of the device policy used to construct the context. This has no 112 // effect on the device policy used by other program threads. 113 TF_CAPI_EXPORT extern void TFE_ContextSetThreadLocalDevicePlacementPolicy( 114 TFE_Context* ctx, TFE_ContextDevicePlacementPolicy policy); 115 116 // Returns the device placement policy to be used by this context in the current 117 // thread. 118 TF_CAPI_EXPORT extern TFE_ContextDevicePlacementPolicy 119 TFE_ContextGetDevicePlacementPolicy(TFE_Context* ctx); 120 121 // A tensorflow.ServerDef specifies remote workers (in addition to the current 122 // workers name). Operations created on this context can then be executed on 123 // any of these remote workers by setting an appropriate device. 124 // 125 // If the following is set, all servers identified by the 126 // ServerDef must be up when the context is created. 127 TF_CAPI_EXPORT extern void TFE_ContextSetServerDef(TFE_Context* ctx, 128 int keep_alive_secs, 129 const void* proto, 130 size_t proto_len, 131 TF_Status* status); 132 133 // A handle to a tensor on a device. 134 // 135 // Like a TF_Tensor, a TFE_TensorHandle refers to a tensor with a value, shape, 136 // type etc. Unlike a TF_Tensor, a TFE_TensorHandle may refer to such tensors 137 // placed in memory of different devices or remote address spaces. 138 typedef struct TFE_TensorHandle TFE_TensorHandle; 139 140 TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_NewTensorHandle(TF_Tensor* t, 141 TF_Status* status); 142 // Indicates that the caller will not be using `h` any more. 143 TF_CAPI_EXPORT extern void TFE_DeleteTensorHandle(TFE_TensorHandle* h); 144 TF_CAPI_EXPORT extern TF_DataType TFE_TensorHandleDataType(TFE_TensorHandle* h); 145 // This function will block till the operation that produces `h` has completed. 146 TF_CAPI_EXPORT extern int TFE_TensorHandleNumDims(TFE_TensorHandle* h, 147 TF_Status* status); 148 TF_CAPI_EXPORT extern int64_t TFE_TensorHandleNumElements(TFE_TensorHandle* h, 149 TF_Status* status); 150 // This function will block till the operation that produces `h` has completed. 151 TF_CAPI_EXPORT extern int64_t TFE_TensorHandleDim(TFE_TensorHandle* h, 152 int dim_index, 153 TF_Status* status); 154 155 // Returns the device of the operation that produced `h`. If `h` was produced by 156 // a copy, returns the destination device of the copy. Note that the returned 157 // device name is not always the device holding the tensor handle's memory. If 158 // you want the latter, use TFE_TensorHandleBackingDeviceName. This function 159 // will block till the operation that produces `h` has completed. 160 TF_CAPI_EXPORT extern const char* TFE_TensorHandleDeviceName( 161 TFE_TensorHandle* h, TF_Status* status); 162 163 // Returns the name of the device in whose memory `h` resides. 164 // 165 // This function will block till the operation that produces `h` has completed. 166 TF_CAPI_EXPORT extern const char* TFE_TensorHandleBackingDeviceName( 167 TFE_TensorHandle* h, TF_Status* status); 168 169 // Return a pointer to a new TFE_TensorHandle that shares the underlying tensor 170 // with `h`. On success, `status` is set to OK. On failure, `status` reflects 171 // the error and a nullptr is returned. 172 TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopySharingTensor( 173 TFE_TensorHandle* h, TF_Status* status); 174 175 // This function will block till the operation that produces `h` has 176 // completed. The memory returned might alias the internal memory used by 177 // TensorFlow. Hence, callers should not mutate this memory (for example by 178 // modifying the memory region pointed to by TF_TensorData() on the returned 179 // TF_Tensor). 180 TF_CAPI_EXPORT extern TF_Tensor* TFE_TensorHandleResolve(TFE_TensorHandle* h, 181 TF_Status* status); 182 183 // Create a new TFE_TensorHandle with the same contents as 'h' but placed 184 // in the memory of the device name 'device_name'. 185 // If source and destination are the same device, then this creates a new handle 186 // that shares the underlying buffer. Otherwise, it currently requires at least 187 // one of the source or destination devices to be CPU (i.e., for the source or 188 // destination tensor to be placed in host memory). 189 // If async execution is enabled, the copy may be enqueued and the call will 190 // return "non-ready" handle. Else, this function returns after the copy has 191 // been done. 192 TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopyToDevice( 193 TFE_TensorHandle* h, TFE_Context* ctx, const char* device_name, 194 TF_Status* status); 195 196 // Debugging/Profiling information for TFE_TensorHandle 197 // 198 // TFE_TensorDebugInfo contains information useful for debugging and 199 // profiling tensors. 200 typedef struct TFE_TensorDebugInfo TFE_TensorDebugInfo; 201 202 // Retrieves TFE_TensorDebugInfo for `handle`. 203 // If TFE_TensorHandleTensorDebugInfo succeeds, `status` is set to OK and caller 204 // is responsible for deleting returned TFE_TensorDebugInfo. 205 // If TFE_TensorHandleTensorDebugInfo fails, `status` is set to appropriate 206 // error and nullptr is returned. This function can block till the operation 207 // that produces `handle` has completed. 208 TF_CAPI_EXPORT extern TFE_TensorDebugInfo* TFE_TensorHandleTensorDebugInfo( 209 TFE_TensorHandle* h, TF_Status* status); 210 211 // Deletes `debug_info`. 212 TF_CAPI_EXPORT extern void TFE_DeleteTensorDebugInfo( 213 TFE_TensorDebugInfo* debug_info); 214 215 // Returns the number of dimensions used to represent the tensor on its device. 216 // The number of dimensions used to represent the tensor on device can be 217 // different from the number returned by TFE_TensorHandleNumDims. 218 // The return value was current at the time of TFE_TensorDebugInfo creation. 219 TF_CAPI_EXPORT extern int TFE_TensorDebugInfoOnDeviceNumDims( 220 TFE_TensorDebugInfo* debug_info); 221 222 // Returns the number of elements in dimension `dim_index`. 223 // Tensor representation on device can be transposed from its representation 224 // on host. The data contained in dimension `dim_index` on device 225 // can correspond to the data contained in another dimension in on-host 226 // representation. The dimensions are indexed using the standard TensorFlow 227 // major-to-minor order (slowest varying dimension first), 228 // not the XLA's minor-to-major order. 229 // On-device dimensions can be padded. TFE_TensorDebugInfoOnDeviceDim returns 230 // the number of elements in a dimension after padding. 231 // The return value was current at the time of TFE_TensorDebugInfo creation. 232 TF_CAPI_EXPORT extern int64_t TFE_TensorDebugInfoOnDeviceDim( 233 TFE_TensorDebugInfo* debug_info, int dim_index); 234 235 // Description of the TensorFlow op to execute. 236 // 237 // Assumes that the provided 'ctx' outlives the returned TFE_Op, i.e., 238 // TFE_DeleteOp() is called before TFE_DeleteContext(). 239 // 240 // Very similar to TF_OperationDescription with some differences: 241 // (1) TF_Output or TFE_TensorHandle* as arguments to TF_AddInput, 242 // TF_AddInputList 243 // (2) TF_ColocateWith, TF_AddControlInput etc. do not make sense. 244 // (3) Implementation detail: Avoid use of NodeBuilder/NodeDefBuilder since 245 // the additional sanity checks there seem unnecessary; 246 typedef struct TFE_Op TFE_Op; 247 248 TF_CAPI_EXPORT extern TFE_Op* TFE_NewOp(TFE_Context* ctx, 249 const char* op_or_function_name, 250 TF_Status* status); 251 252 TF_CAPI_EXPORT extern void TFE_DeleteOp(TFE_Op* op); 253 254 TF_CAPI_EXPORT extern void TFE_OpSetDevice(TFE_Op* op, const char* device_name, 255 TF_Status* status); 256 // The returned string remains valid throughout the lifetime of 'op'. 257 TF_CAPI_EXPORT extern const char* TFE_OpGetDevice(TFE_Op* op, 258 TF_Status* status); 259 260 // When 'enable' is set to 1, and if TensorFlow library is built with XLA 261 // support, a subsequent TFE_Execute() call on `op` will run the op via XLA. 262 // 263 // If the library is not built with XLA support, this call would be a no-op. 264 TF_CAPI_EXPORT extern void TFE_OpSetXLACompilation(TFE_Op* op, 265 unsigned char enable); 266 267 TF_CAPI_EXPORT extern void TFE_OpAddInput(TFE_Op* op, TFE_TensorHandle* input, 268 TF_Status* status); 269 270 TF_CAPI_EXPORT extern void TFE_OpAddInputList(TFE_Op* op, 271 TFE_TensorHandle** inputs, 272 int num_inputs, 273 TF_Status* status); 274 275 TF_CAPI_EXPORT extern TF_AttrType TFE_OpGetAttrType(TFE_Op* op, 276 const char* attr_name, 277 unsigned char* is_list, 278 TF_Status* status); 279 // Get an attribute type given an op name; a fusion of TFE_NewOp and 280 // TFE_OpGetAttrType for use from Python without the overhead of the individual 281 // calls and memory management of TFE_Op. 282 TF_CAPI_EXPORT extern TF_AttrType TFE_OpNameGetAttrType( 283 TFE_Context* ctx, const char* op_or_function_name, const char* attr_name, 284 unsigned char* is_list, TF_Status* status); 285 286 TF_CAPI_EXPORT extern void TFE_OpSetAttrString(TFE_Op* op, 287 const char* attr_name, 288 const void* value, 289 size_t length); 290 TF_CAPI_EXPORT extern void TFE_OpSetAttrInt(TFE_Op* op, const char* attr_name, 291 int64_t value); 292 TF_CAPI_EXPORT extern void TFE_OpSetAttrFloat(TFE_Op* op, const char* attr_name, 293 float value); 294 TF_CAPI_EXPORT extern void TFE_OpSetAttrBool(TFE_Op* op, const char* attr_name, 295 unsigned char value); 296 TF_CAPI_EXPORT extern void TFE_OpSetAttrType(TFE_Op* op, const char* attr_name, 297 TF_DataType value); 298 // If the number of dimensions is unknown, `num_dims` must be set to 299 // -1 and `dims` can be null. If a dimension is unknown, the 300 // corresponding entry in the `dims` array must be -1. 301 TF_CAPI_EXPORT extern void TFE_OpSetAttrShape(TFE_Op* op, const char* attr_name, 302 const int64_t* dims, 303 const int num_dims, 304 TF_Status* out_status); 305 306 // Sets the attribute attr_name to be a function specified by 'function'. 307 // 308 // TODO(ashankar,iga): Add this functionality to the C API for graph 309 // construction. Perhaps we want an AttrValueMap equivalent in the C API? 310 TF_CAPI_EXPORT extern void TFE_OpSetAttrFunction(TFE_Op* op, 311 const char* attr_name, 312 const TFE_Op* value); 313 314 TF_CAPI_EXPORT void TFE_OpSetAttrFunctionName(TFE_Op* op, const char* attr_name, 315 const char* data, size_t length); 316 317 TF_CAPI_EXPORT extern void TFE_OpSetAttrTensor(TFE_Op* op, 318 const char* attr_name, 319 TF_Tensor* tensor, 320 TF_Status* status); 321 322 TF_CAPI_EXPORT extern void TFE_OpSetAttrStringList(TFE_Op* op, 323 const char* attr_name, 324 const void* const* values, 325 const size_t* lengths, 326 int num_values); 327 TF_CAPI_EXPORT extern void TFE_OpSetAttrIntList(TFE_Op* op, 328 const char* attr_name, 329 const int64_t* values, 330 int num_values); 331 TF_CAPI_EXPORT extern void TFE_OpSetAttrFloatList(TFE_Op* op, 332 const char* attr_name, 333 const float* values, 334 int num_values); 335 TF_CAPI_EXPORT extern void TFE_OpSetAttrBoolList(TFE_Op* op, 336 const char* attr_name, 337 const unsigned char* values, 338 int num_values); 339 TF_CAPI_EXPORT extern void TFE_OpSetAttrTypeList(TFE_Op* op, 340 const char* attr_name, 341 const TF_DataType* values, 342 int num_values); 343 TF_CAPI_EXPORT extern void TFE_OpSetAttrShapeList( 344 TFE_Op* op, const char* attr_name, const int64_t** dims, 345 const int* num_dims, int num_values, TF_Status* out_status); 346 TF_CAPI_EXPORT extern void TFE_OpSetAttrFunctionList(TFE_Op* op, 347 const char* attr_name, 348 const TFE_Op** value, 349 int num_values); 350 351 // Returns the length (number of tensors) of the input argument `input_name` 352 // found in the provided `op`. 353 TF_CAPI_EXPORT extern int TFE_OpGetInputLength(TFE_Op* op, 354 const char* input_name, 355 TF_Status* status); 356 357 // Returns the length (number of tensors) of the output argument `output_name` 358 // found in the provided `op`. 359 TF_CAPI_EXPORT extern int TFE_OpGetOutputLength(TFE_Op* op, 360 const char* output_name, 361 TF_Status* status); 362 363 // Execute the operation defined by 'op' and return handles to computed 364 // tensors in `retvals`. 365 // 366 // 'retvals' must point to a pre-allocated array of TFE_TensorHandle* and 367 // '*num_retvals' should be set to the size of this array. It is an error if 368 // the size of 'retvals' is less than the number of outputs. This call sets 369 // *num_retvals to the number of outputs. 370 // 371 // If async execution is enabled, the call may simply enqueue the execution 372 // and return "non-ready" handles in `retvals`. Note that any handles contained 373 // in 'op' should not be mutated till the kernel execution actually finishes. 374 // 375 // For sync execution, if any of the inputs to `op` are not ready, this call 376 // will block till they become ready and then return when the kernel execution 377 // is done. 378 // TODO(agarwal): change num_retvals to int from int*. 379 TF_CAPI_EXPORT extern void TFE_Execute(TFE_Op* op, TFE_TensorHandle** retvals, 380 int* num_retvals, TF_Status* status); 381 382 // Add a function (serialized FunctionDef protocol buffer) to ctx so 383 // that it can be invoked using TFE_Execute. 384 TF_CAPI_EXPORT extern void TFE_ContextAddFunctionDef( 385 TFE_Context* ctx, const char* serialized_function_def, size_t size, 386 TF_Status* status); 387 388 // Adds a function (created from TF_GraphToFunction or 389 // TF_FunctionImportFunctionDef) to the context, allowing it to be executed with 390 // TFE_Execute by creating an op with the same name as the function. 391 TF_CAPI_EXPORT extern void TFE_ContextAddFunction(TFE_Context* ctx, 392 TF_Function* function, 393 TF_Status* status); 394 395 // Removes a function from the context. Once removed, you can no longer 396 // TFE_Execute it or TFE_Execute any TFE_Op which has it as an attribute or any 397 // other function which calls it as an attribute. 398 TF_CAPI_EXPORT extern void TFE_ContextRemoveFunction(TFE_Context* ctx, 399 const char* name, 400 TF_Status* status); 401 402 // Checks whether a function is registered under `name`. 403 TF_CAPI_EXPORT unsigned char TFE_ContextHasFunction(TFE_Context* ctx, 404 const char* name); 405 406 // Enables tracing of RunMetadata on the ops executed from this context. 407 TF_CAPI_EXPORT extern void TFE_ContextEnableRunMetadata(TFE_Context* ctx); 408 409 // Disables tracing of RunMetadata on the ops executed from this context. 410 TF_CAPI_EXPORT extern void TFE_ContextDisableRunMetadata(TFE_Context* ctx); 411 412 // Populates the passed-in buffer with a serialized RunMetadata protocol buffer 413 // containing any run metadata information accumulated so far and clears this 414 // information. 415 // If async mode is enabled, this call blocks till all currently pending ops are 416 // done. 417 TF_CAPI_EXPORT extern void TFE_ContextExportRunMetadata(TFE_Context* ctx, 418 TF_Buffer* buf, 419 TF_Status* status); 420 421 // Some TF ops need a step container to be set to limit the lifetime of some 422 // resources (mostly TensorArray and Stack, used in while loop gradients in 423 // graph mode). Calling this on a context tells it to start a step. 424 TF_CAPI_EXPORT extern void TFE_ContextStartStep(TFE_Context* ctx); 425 426 // Ends a step. When there is no active step (that is, every started step has 427 // been ended) step containers will be cleared. Note: it is not safe to call 428 // TFE_ContextEndStep while ops which rely on the step container may be running. 429 TF_CAPI_EXPORT extern void TFE_ContextEndStep(TFE_Context* ctx); 430 431 #ifdef __cplusplus 432 } /* end extern "C" */ 433 #endif 434 435 #ifdef __cplusplus 436 // A workaround to ease conversion to and from numpy objects and 437 // TFE_TensorHandle's. 438 // 439 // TODO(ashankar): Figure out an alternative scheme that precludes the need for 440 // these API-boundary breaking methods. 441 namespace tensorflow { 442 class Tensor; 443 } // namespace tensorflow 444 445 TFE_TensorHandle* TFE_NewTensorHandle(const tensorflow::Tensor& t, 446 TF_Status* status); 447 #endif 448 449 #endif // TENSORFLOW_C_EAGER_C_API_H_ 450