tvm
Loading...
Searching...
No Matches
tensor.h
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
24#ifndef TVM_RUNTIME_TENSOR_H_
25#define TVM_RUNTIME_TENSOR_H_
26
27#include <tvm/ffi/container/shape.h>
28#include <tvm/ffi/container/tensor.h>
29#include <tvm/ffi/dtype.h>
30#include <tvm/ffi/optional.h>
31#include <tvm/ffi/string.h>
32#include <tvm/runtime/base.h>
34#include <tvm/support/io.h>
36
37#include <atomic>
38#include <functional>
39#include <utility>
40#include <vector>
41
42namespace tvm {
43namespace runtime {
44
49class Tensor : public tvm::ffi::Tensor {
50 public:
51 Tensor() = default;
56 explicit Tensor(ffi::ObjectPtr<ffi::TensorObj> data) : tvm::ffi::Tensor(data) {}
57 explicit Tensor(ffi::UnsafeInit tag) : tvm::ffi::Tensor(tag) {}
58 Tensor(ffi::Tensor&& other) : tvm::ffi::Tensor(std::move(other)) {} // NOLINT(*)
59 Tensor(const ffi::Tensor& other) : tvm::ffi::Tensor(other) {} // NOLINT(*)
60
61 ffi::ShapeView Shape() const { return this->shape(); }
62 DLDataType DataType() const { return this->dtype(); }
63
64 // DLPack handling
66 return tvm::ffi::Tensor::FromDLPack(tensor, kAllocAlignment, true);
67 }
68
70 return tvm::ffi::Tensor::FromDLPackVersioned(tensor, kAllocAlignment, true);
71 }
72 inline const DLTensor* operator->() const { return this->get(); }
79 inline void CopyFrom(const DLTensor* other);
80 inline void CopyFrom(const Tensor& other);
88 TVM_RUNTIME_DLL void CopyFromBytes(const void* data, size_t nbytes);
95 inline void CopyTo(DLTensor* other) const;
96 inline void CopyTo(const Tensor& other) const;
104 TVM_RUNTIME_DLL void CopyToBytes(void* data, size_t nbytes) const;
113 ffi::Optional<ffi::String> mem_scope = std::nullopt) const;
119 inline bool Load(support::Stream* stream);
124 inline void Save(support::Stream* stream) const;
125
156 TVM_RUNTIME_DLL static Tensor Empty(ffi::Shape shape, DLDataType dtype, Device dev,
157 ffi::Optional<ffi::String> mem_scope = std::nullopt);
165 TVMStreamHandle stream = nullptr);
166
174 TVM_RUNTIME_DLL static void CopyToBytes(const DLTensor* from, void* to, size_t nbytes,
175 TVMStreamHandle stream = nullptr);
176
184 TVM_RUNTIME_DLL static void CopyFromBytes(const DLTensor* to, void* from, size_t nbytes,
185 TVMStreamHandle stream = nullptr);
186
197 TVM_RUNTIME_DLL static bool IsStorageShared(const DLTensor* a, const DLTensor* b);
198
205 static bool IsStorageShared(const Tensor& a, const Tensor& b);
206};
207
213inline bool SaveDLTensor(support::Stream* strm, const DLTensor* tensor);
214
215inline void Tensor::CopyFrom(const DLTensor* other) {
216 TVM_FFI_ICHECK(data_ != nullptr);
217 CopyFromTo(other, get_mutable());
218}
219
220inline void Tensor::CopyFrom(const Tensor& other) {
221 TVM_FFI_ICHECK(data_ != nullptr);
222 TVM_FFI_ICHECK(other.data_ != nullptr);
223 CopyFromTo(other.get_mutable(), get_mutable());
224}
225
226inline void Tensor::CopyTo(DLTensor* other) const {
227 TVM_FFI_ICHECK(data_ != nullptr);
228 CopyFromTo(get_mutable(), other);
229}
230
231inline void Tensor::CopyTo(const Tensor& other) const {
232 TVM_FFI_ICHECK(data_ != nullptr);
233 TVM_FFI_ICHECK(other.data_ != nullptr);
234 CopyFromTo(get_mutable(), other.get_mutable());
235}
236
238constexpr uint64_t kTVMTensorMagic = 0xDD5E40F096B4A13F;
239
240inline bool SaveDLTensor(support::Stream* strm, const DLTensor* tensor) {
242 strm->Write(header);
243 strm->Write(reserved);
244 // Always save data as CPU context
245 //
246 // Parameters that get serialized should be in CPU by default.
247 // So even the array's context is GPU, it will be stored as CPU array.
248 // This is used to prevent case when another user loads the parameters
249 // back on machine that do not have GPU or related context.
250 //
251 // We can always do array.CopyTo(target_dev) to get a corresponding
252 // array in the target context.
254 cpu_dev.device_type = kDLCPU;
255 cpu_dev.device_id = 0;
256 strm->Write(cpu_dev);
257 strm->Write(tensor->ndim);
258 strm->Write(tensor->dtype);
259 int ndim = tensor->ndim;
260 strm->WriteArray(tensor->shape, ndim);
261 int type_bytes = (tensor->dtype.bits + 7) / 8;
262 int64_t num_elems = 1;
263 for (int i = 0; i < ndim; ++i) {
264 num_elems *= tensor->shape[i];
265 }
267 strm->Write(data_byte_size);
268
269 if (TVM_FFI_IO_NO_ENDIAN_SWAP && tensor->device.device_type == kDLCPU &&
270 ffi::IsContiguous(*tensor) && tensor->byte_offset == 0) {
271 // quick path
272 strm->Write(tensor->data, data_byte_size);
273 } else {
274 std::vector<uint8_t> bytes(data_byte_size);
275 Tensor::CopyToBytes(const_cast<DLTensor*>(tensor), bytes.data(), data_byte_size);
277 ffi::ByteSwap(bytes.data(), type_bytes, num_elems);
278 }
279 strm->Write(bytes.data(), data_byte_size);
280 }
281 return true;
282}
283
285
288 TVM_FFI_ICHECK(strm->Read(&header)) << "Invalid DLTensor file format";
289 TVM_FFI_ICHECK(strm->Read(&reserved)) << "Invalid DLTensor file format";
290 TVM_FFI_ICHECK(header == kTVMTensorMagic) << "Invalid DLTensor file format";
291 Device dev;
292 int ndim;
293 DLDataType dtype;
294 TVM_FFI_ICHECK(strm->Read(&dev)) << "Invalid DLTensor file format";
295 TVM_FFI_ICHECK(strm->Read(&ndim)) << "Invalid DLTensor file format";
296 TVM_FFI_ICHECK(strm->Read(&dtype)) << "Invalid DLTensor file format";
297 TVM_FFI_ICHECK_EQ(dev.device_type, kDLCPU)
298 << "Invalid DLTensor device: can only save as CPU tensor";
299 std::vector<int64_t> shape(ndim);
300 if (ndim != 0) {
301 TVM_FFI_ICHECK(strm->ReadArray(&shape[0], ndim)) << "Invalid DLTensor file format";
302 }
303 Tensor ret = Tensor::Empty(ffi::Shape(shape), dtype, dev);
304 int64_t num_elems = 1;
305 int elem_bytes = (ret->dtype.bits + 7) / 8;
306 for (int i = 0; i < ret->ndim; ++i) {
307 num_elems *= ret->shape[i];
308 }
310 TVM_FFI_ICHECK(strm->Read(&data_byte_size)) << "Invalid DLTensor file format";
311 TVM_FFI_ICHECK(data_byte_size == num_elems * elem_bytes) << "Invalid DLTensor file format";
312 auto read_ret = strm->Read(ret->data, data_byte_size);
313 // Only check non-empty data
314 if (ndim > 0 && shape[0] != 0) {
315 TVM_FFI_ICHECK(read_ret) << "Invalid DLTensor file format";
316 }
318 ffi::ByteSwap(ret->data, elem_bytes, num_elems);
319 }
320 *this = ret;
321 return true;
322}
323
331 if (device.device_type == DLDeviceType::kDLCUDA) {
332 return Device{DLDeviceType::kDLCUDAHost, 0};
333 } else if (device.device_type == DLDeviceType::kDLROCM) {
334 return Device{DLDeviceType::kDLROCMHost, 0};
335 } else {
336 // Fallback to CPU.
337 return Device{DLDeviceType::kDLCPU, 0};
338 }
339}
340
341} // namespace runtime
342} // namespace tvm
343
344namespace std {
345template <>
346struct hash<tvm::Device> {
347 std::size_t operator()(const tvm::Device& dev) const {
348 return ((dev.device_id << 8) | dev.device_type);
349 }
350};
351
352template <>
353struct equal_to<tvm::Device> {
354 bool operator()(const tvm::Device& lhs, const tvm::Device& rhs) const {
355 return (lhs.device_type == rhs.device_type && lhs.device_id == rhs.device_id);
356 }
357};
358} // namespace std
359
360#endif // TVM_RUNTIME_TENSOR_H_
RAII wrapper function to enter and exit a context object similar to python's with syntax.
Definition with_context.h:59
Managed Tensor. The array is backed by reference counted blocks.
Definition tensor.h:49
const DLTensor * operator->() const
Definition tensor.h:72
static bool IsStorageShared(const Tensor &a, const Tensor &b)
Tensor overload of IsStorageShared.
static TVM_RUNTIME_DLL void CopyToBytes(const DLTensor *from, void *to, size_t nbytes, TVMStreamHandle stream=nullptr)
Function to copy data from one array to a byte buffer.
static TVM_RUNTIME_DLL Tensor Empty(ffi::Shape shape, DLDataType dtype, Device dev, ffi::Optional< ffi::String > mem_scope=std::nullopt)
Create an empty Tensor.
static Tensor FromDLPackVersioned(DLManagedTensorVersioned *tensor)
Definition tensor.h:69
TVM_RUNTIME_DLL void CopyToBytes(void *data, size_t nbytes) const
Copy data content into another array.
DLDataType DataType() const
Definition tensor.h:62
bool Load(support::Stream *stream)
Load Tensor from stream.
Definition tensor.h:286
static TVM_RUNTIME_DLL bool IsStorageShared(const DLTensor *a, const DLTensor *b)
Check if two tensors share the same underlying storage.
void CopyFrom(const DLTensor *other)
Copy data content from another array.
Definition tensor.h:215
TVM_RUNTIME_DLL Tensor CopyTo(const Device &dev, ffi::Optional< ffi::String > mem_scope=std::nullopt) const
Copy the data to another device.
void Save(support::Stream *stream) const
Save Tensor to stream.
Definition tensor.h:284
ffi::ShapeView Shape() const
Definition tensor.h:61
Tensor(ffi::UnsafeInit tag)
Definition tensor.h:57
void CopyTo(DLTensor *other) const
Copy data content into another array.
Definition tensor.h:226
static TVM_RUNTIME_DLL void CopyFromTo(const DLTensor *from, DLTensor *to, TVMStreamHandle stream=nullptr)
Function to copy data from one array to another.
Tensor(const ffi::Tensor &other)
Definition tensor.h:59
Tensor(ffi::Tensor &&other)
Definition tensor.h:58
Tensor(ffi::ObjectPtr< ffi::TensorObj > data)
constructor.
Definition tensor.h:56
TVM_RUNTIME_DLL void CopyFromBytes(const void *data, size_t nbytes)
Copy data content from a byte buffer.
static Tensor FromDLPack(DLManagedTensor *tensor)
Definition tensor.h:65
TVM_RUNTIME_DLL Tensor CreateView(ffi::Shape shape, DLDataType dtype, uint64_t relative_byte_offset=0) const
Create a Tensor that shares the data memory with the current one.
static TVM_RUNTIME_DLL void CopyFromBytes(const DLTensor *to, void *from, size_t nbytes, TVMStreamHandle stream=nullptr)
Function to copy data from one array to a byte buffer.
Abstract binary stream for serialization.
Definition io.h:57
Abstract device memory management API.
void * TVMStreamHandle
The stream that is specific to device can be NULL, which indicates the default one.
Definition device_api.h:39
Binary stream I/O interface.
bool SaveDLTensor(support::Stream *strm, const DLTensor *tensor)
Save a DLTensor to stream.
Definition tensor.h:240
Device GetPreferredHostDevice(Device device)
Get the preferred host device from the input device.
Definition tensor.h:330
constexpr int kAllocAlignment
Number of bytes each allocation must align to.
Definition device_api.h:113
constexpr uint64_t kTVMTensorMagic
Magic number for Tensor file.
Definition tensor.h:238
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition analyzer.h:40
DLDevice Device
Definition device_api.h:44
#define TVM_RUNTIME_DLL
Definition base.h:92
Serializer<T> specializations for tvm::support::Stream.