Home | History | Annotate | Download | only in tf2xla
      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 #include "tensorflow/compiler/tf2xla/xla_compilation_device.h"
     17 
     18 #include <functional>
     19 #include <memory>
     20 
     21 #include "tensorflow/compiler/tf2xla/shape_util.h"
     22 #include "tensorflow/compiler/tf2xla/sharding_util.h"
     23 #include "tensorflow/compiler/tf2xla/xla_context.h"
     24 #include "tensorflow/compiler/tf2xla/xla_helpers.h"
     25 #include "tensorflow/core/common_runtime/local_device.h"
     26 #include "tensorflow/core/framework/device_base.h"
     27 #include "tensorflow/core/platform/mem.h"
     28 
     29 namespace tensorflow {
     30 
     31 // The XlaCompilationAllocator doesn't actually back any Tensors with storage
     32 // buffers of values: instead for each Tensor it stores a
     33 // XlaExpression which corresponds to the XLA computation
     34 // represented by the Tensor.
     35 class XlaCompilationAllocator : public Allocator {
     36  public:
     37   XlaCompilationAllocator() {}
     38   ~XlaCompilationAllocator() override {}
     39 
     40   string Name() override { return "xla_compilation"; }
     41 
     42   void* AllocateRaw(size_t alignment, size_t num_bytes) override {
     43     // Regardless of the size requested, always allocates an XlaExpression.
     44     // Respects the aligment request because there is alignment checking even
     45     // for Tensors whose data is never accessed.
     46     void* p = port::AlignedMalloc(sizeof(XlaExpression), alignment);
     47     XlaExpression* expression = reinterpret_cast<XlaExpression*>(p);
     48     new (expression) XlaExpression();
     49     return expression;
     50   }
     51 
     52   void DeallocateRaw(void* ptr) override {
     53     XlaExpression* expression = reinterpret_cast<XlaExpression*>(ptr);
     54     expression->~XlaExpression();
     55     port::AlignedFree(ptr);
     56   }
     57 
     58   // Make sure that even tensors with 0 elements have allocated
     59   // buffers, so they get ids to track.
     60   bool ShouldAllocateEmptyTensors() override { return true; }
     61 
     62   void GetStats(AllocatorStats* stats) override { stats->Clear(); }
     63 
     64  private:
     65   // Don't run any constructors or destructors for complex objects,
     66   // since there is no backing store for the tensor to run them
     67   // on. strings are the only complex objects currently stored in
     68   // Tensors. If others are added, this set of overrides must be
     69   // extended to include them.
     70   void RunStringCtor(string* p, size_t n) override {}
     71   void RunStringDtor(string* p, size_t n) override {}
     72   void RunResourceCtor(ResourceHandle* p, size_t n) override {}
     73   void RunResourceDtor(ResourceHandle* p, size_t n) override {}
     74 };
     75 
     76 XlaCompilationDevice::XlaCompilationDevice(const SessionOptions& options,
     77                                            DeviceType type)
     78     : LocalDevice(
     79           options,
     80           Device::BuildDeviceAttributes(
     81               strings::StrCat("/device:", type.type(), ":0"), type,
     82               Bytes(256 << 20), DeviceLocality(),
     83               strings::StrCat("device: XLA compilation device ", type.type()))),
     84       allocator_(new XlaCompilationAllocator()) {}
     85 
     86 XlaCompilationDevice::~XlaCompilationDevice() {}
     87 
     88 Allocator* XlaCompilationDevice::GetAllocator(AllocatorAttributes attr) {
     89   return allocator_.get();
     90 }
     91 
     92 void XlaCompilationDevice::Compute(OpKernel* op_kernel,
     93                                    OpKernelContext* context) {
     94   VLOG(4) << "XlaCompilationDevice::Compute "
     95           << SummarizeNodeDef(op_kernel->def());
     96   auto* b = XlaContext::Get(context).builder();
     97   xla::OpMetadata metadata;
     98   metadata.set_op_type(op_kernel->type_string());
     99   metadata.set_op_name(op_kernel->name());
    100   b->SetOpMetadata(metadata);
    101 
    102   auto sharding_parse_result = ParseShardingFromDevice(
    103       op_kernel->def(), std::numeric_limits<int>::max());
    104   OP_REQUIRES_OK(context, sharding_parse_result.status());
    105   tensorflow::gtl::optional<xla::OpSharding> op_sharding =
    106       sharding_parse_result.ValueOrDie();
    107 
    108   // If no sharding metadata is found, XLA is free to use whatever device it
    109   // wants. In practice this usually has the effect of placing things on device
    110   // 0.
    111   xla::ScopedShardingAssignment assign_sharding(b, op_sharding);
    112   op_kernel->Compute(context);
    113 
    114   b->ClearOpMetadata();
    115   VLOG(4) << "Done";
    116 }
    117 
    118 Status XlaCompilationDevice::Sync() { return Status::OK(); }
    119 
    120 Status XlaCompilationDevice::MakeTensorFromProto(
    121     const TensorProto& tensor_proto, const AllocatorAttributes alloc_attrs,
    122     Tensor* tensor) {
    123   return errors::InvalidArgument(
    124       "XLACompilationDevice::MakeTensorFromProto should not be called");
    125 }
    126 
    127 XlaExpression::XlaExpression() = default;
    128 
    129 void XlaExpression::set_handle(const xla::ComputationDataHandle& h) {
    130   handle_ = h;
    131 }
    132 
    133 void XlaExpression::set_constant_value(Tensor value) {
    134   has_constant_value_ = true;
    135   constant_value_ = std::move(value);
    136 }
    137 
    138 }  // namespace tensorflow
    139