• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/frontend_attributes_util.h"
22 #include "tensorflow/compiler/tf2xla/shape_util.h"
23 #include "tensorflow/compiler/tf2xla/sharding_util.h"
24 #include "tensorflow/compiler/tf2xla/xla_context.h"
25 #include "tensorflow/compiler/tf2xla/xla_helpers.h"
26 #include "tensorflow/compiler/xla/client/xla_builder.h"
27 #include "tensorflow/core/common_runtime/local_device.h"
28 #include "tensorflow/core/framework/device_base.h"
29 #include "tensorflow/core/platform/mem.h"
30 
31 namespace tensorflow {
32 
33 // The XlaCompilationAllocator doesn't actually back any Tensors with storage
34 // buffers of values: instead for each Tensor it stores a
35 // XlaExpression which corresponds to the XLA computation
36 // represented by the Tensor.
37 class XlaCompilationAllocator : public Allocator {
38  public:
XlaCompilationAllocator()39   XlaCompilationAllocator() {}
~XlaCompilationAllocator()40   ~XlaCompilationAllocator() override {}
41 
Name()42   string Name() override { return "xla_compilation"; }
43 
AllocateRaw(size_t alignment,size_t num_bytes)44   void* AllocateRaw(size_t alignment, size_t num_bytes) override {
45     // Regardless of the size requested, always allocates an XlaExpression.
46     // Respects the alignment request because there is alignment checking even
47     // for Tensors whose data is never accessed.
48     void* p = port::AlignedMalloc(sizeof(XlaExpression), alignment);
49     XlaExpression* expression = reinterpret_cast<XlaExpression*>(p);
50     new (expression) XlaExpression();
51     return expression;
52   }
53 
DeallocateRaw(void * ptr)54   void DeallocateRaw(void* ptr) override {
55     XlaExpression* expression = reinterpret_cast<XlaExpression*>(ptr);
56     expression->~XlaExpression();
57     port::AlignedFree(ptr);
58   }
59 
60   // Make sure that even tensors with 0 elements have allocated
61   // buffers, so they get ids to track.
62   //
63   // NOTE: It is the caller's responsibility to track whether an allocated
64   // object is a buffer or an opaque handle. In particular, when this allocator
65   // is used, the caller must not run any constructors or destructors for
66   // complex objects, since there is no backing store for the tensor in which to
67   // place their outputs.
AllocatesOpaqueHandle() const68   bool AllocatesOpaqueHandle() const override { return true; }
69 };
70 
XlaCompilationDevice(const SessionOptions & options,DeviceType type)71 XlaCompilationDevice::XlaCompilationDevice(const SessionOptions& options,
72                                            DeviceType type)
73     : LocalDevice(options, Device::BuildDeviceAttributes(
74                                absl::StrCat("/device:", type.type(), ":0"),
75                                type, Bytes(256 << 20), DeviceLocality(),
76                                absl::StrCat("device: XLA compilation device ",
77                                             type.type()))),
78       allocator_(new XlaCompilationAllocator()) {}
79 
~XlaCompilationDevice()80 XlaCompilationDevice::~XlaCompilationDevice() {}
81 
GetAllocator(AllocatorAttributes attr)82 Allocator* XlaCompilationDevice::GetAllocator(AllocatorAttributes attr) {
83   return allocator_.get();
84 }
85 
86 // Attaches location from the node stack trace to metadata. As a heuristic,
87 // picks the last frame which does not contain the "tensorflow/python" substring
88 // (making exception for frames containing "test" to allow for testing the
89 // feature).
AttachLocationToMetadata(xla::OpMetadata & metadata,OpKernel * op_kernel,XlaContext & context)90 static void AttachLocationToMetadata(xla::OpMetadata& metadata,
91                                      OpKernel* op_kernel, XlaContext& context) {
92   if (const AbstractStackTrace* stack_trace =
93           context.StackTraceForNodeName(op_kernel->def().name())) {
94     if (absl::optional<StackFrame> frame = stack_trace->LastUserFrame()) {
95       metadata.set_source_file(frame->file_name);
96       metadata.set_source_line(frame->line_number);
97     }
98   }
99 }
100 
Compute(OpKernel * op_kernel,OpKernelContext * context)101 void XlaCompilationDevice::Compute(OpKernel* op_kernel,
102                                    OpKernelContext* context) {
103   VLOG(4) << "XlaCompilationDevice::Compute "
104           << FormatNodeDefForError(op_kernel->def());
105   XlaContext& xla_context = XlaContext::Get(context);
106   auto* b = xla_context.builder();
107   xla::OpMetadata metadata;
108   metadata.set_op_type(op_kernel->type_string());
109   metadata.set_op_name(op_kernel->name());
110   AttachLocationToMetadata(metadata, op_kernel, xla_context);
111   b->SetOpMetadata(metadata);
112 
113   auto sharding_parse_result =
114       ParseShardingFromDevice(op_kernel->def(), std::numeric_limits<int>::max(),
115                               /*add_metadata=*/false);
116   OP_REQUIRES_OK(context, sharding_parse_result.status());
117   absl::optional<xla::OpSharding> op_sharding =
118       sharding_parse_result.ValueOrDie();
119 
120   auto frontend_attributes_result =
121       GetFrontendAttributesFromAttrSlice(AttrSlice(op_kernel->def()));
122   OP_REQUIRES_OK(context, frontend_attributes_result.status());
123   absl::optional<xla::FrontendAttributes> attributes =
124       frontend_attributes_result.ValueOrDie();
125 
126   xla::FrontendAttributes merged_attributes = b->frontend_attributes();
127   if (attributes.has_value()) {
128     merged_attributes.mutable_map()->insert(attributes.value().map().begin(),
129                                             attributes.value().map().end());
130   }
131   xla::XlaScopedFrontendAttributesAssignment assign_frontend_attributes(
132       b, std::move(merged_attributes));
133 
134   // If no sharding metadata is found, XLA is free to use whatever device it
135   // wants. In practice this usually has the effect of placing things on device
136   // 0.
137   xla::XlaScopedShardingAssignment assign_sharding(b, op_sharding);
138   op_kernel->Compute(context);
139 
140   b->ClearOpMetadata();
141   VLOG(4) << "Done";
142 }
143 
Sync()144 Status XlaCompilationDevice::Sync() { return Status::OK(); }
145 
MakeTensorFromProto(const TensorProto & tensor_proto,const AllocatorAttributes alloc_attrs,Tensor * tensor)146 Status XlaCompilationDevice::MakeTensorFromProto(
147     const TensorProto& tensor_proto, const AllocatorAttributes alloc_attrs,
148     Tensor* tensor) {
149   return errors::InvalidArgument(
150       "XLACompilationDevice::MakeTensorFromProto should not be called");
151 }
152 
153 }  // namespace tensorflow
154