tvm
ndarray.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_NDARRAY_H_
25 #define TVM_RUNTIME_NDARRAY_H_
26 
31 #include <tvm/runtime/data_type.h>
32 #include <tvm/runtime/object.h>
33 #include <tvm/runtime/serializer.h>
34 
35 #include <atomic>
36 #include <functional>
37 #include <utility>
38 #include <vector>
39 
40 namespace tvm {
41 
42 // alias DLDevice
43 using Device = DLDevice;
44 
45 // A 'null' device type, does not correspond to any DLDeviceType enum.
46 // TODO(mbs): This is to help us as we transition away from representing the 'homogenous' case
47 // as a singleton target map indexed by the invalid DLDeviceType '0'.
48 constexpr DLDeviceType kNullDeviceType = static_cast<DLDeviceType>(0);
49 
50 // An 'invalid' device type, does not correspond to any DLDeviceType enum.
51 constexpr DLDeviceType kInvalidDeviceType = static_cast<DLDeviceType>(-1);
52 
53 namespace runtime {
54 
59 class NDArray : public ObjectRef {
60  public:
62  class ContainerBase;
64  class Container;
68  NDArray() {}
73  explicit NDArray(ObjectPtr<Object> data) : ObjectRef(data) {}
74 
76  inline void reset();
81  inline int use_count() const;
83  inline const DLTensor* operator->() const;
85  inline bool IsContiguous() const;
92  inline void CopyFrom(const DLTensor* other);
93  inline void CopyFrom(const NDArray& other);
101  TVM_DLL void CopyFromBytes(const void* data, size_t nbytes);
108  inline void CopyTo(DLTensor* other) const;
109  inline void CopyTo(const NDArray& other) const;
117  TVM_DLL void CopyToBytes(void* data, size_t nbytes) const;
123  inline NDArray CopyTo(const Device& dev) const;
129  inline bool Load(dmlc::Stream* stream);
134  inline void Save(dmlc::Stream* stream) const;
141  TVM_DLL NDArray CreateView(ShapeTuple shape, DLDataType dtype);
147  TVM_DLL DLManagedTensor* ToDLPack() const;
156  TVM_DLL static NDArray Empty(ShapeTuple shape, DLDataType dtype, Device dev,
157  Optional<String> mem_scope = NullOpt);
168  TVM_DLL static NDArray FromExternalDLTensor(const DLTensor& dl_tensor);
176  TVM_DLL static NDArray NewFromDLTensor(DLTensor* dl_tensor, const Device& dev);
188  TVM_DLL static NDArray FromDLPack(DLManagedTensor* tensor);
195  TVM_DLL static void CopyFromTo(const DLTensor* from, DLTensor* to,
196  TVMStreamHandle stream = nullptr);
197 
198  TVM_DLL ShapeTuple Shape() const;
199  TVM_DLL runtime::DataType DataType() const;
210  TVM_DLL static bool AbilityOfZeroCopyForDLTensor(DLTensor* tensor, const Device& dev);
211  // internal namespace
212  struct Internal;
213 
214  private:
215  TVM_DLL static bool IsAligned(const DLTensor& tensor);
216 
217  protected:
218  friend class TVMPODValue_;
219  friend class TVMRetValue;
220  friend class TVMArgsSetter;
225  inline Container* get_mutable() const;
226  // Helper functions for FFI handling.
236  inline static ObjectPtr<Object> FFIDataFromHandle(TVMArrayHandle handle);
241  inline static void FFIDecRef(TVMArrayHandle handle);
247  inline static TVMArrayHandle FFIGetHandle(const ObjectRef& nd);
248 };
249 
255 inline bool SaveDLTensor(dmlc::Stream* strm, const DLTensor* tensor);
256 
265  public:
272  DLTensor dl_tensor;
273 
280  void* manager_ctx{nullptr};
281 
282  protected:
288 };
289 
295  public:
298  // Initialize the type index.
299  type_index_ = Container::RuntimeTypeIndex();
300  dl_tensor.data = nullptr;
301  dl_tensor.ndim = 0;
302  dl_tensor.shape = nullptr;
303  dl_tensor.strides = nullptr;
304  dl_tensor.byte_offset = 0;
305  }
306 
307  Container(void* data, ShapeTuple shape, DLDataType dtype, Device dev) {
308  // Initialize the type index.
309  type_index_ = Container::RuntimeTypeIndex();
310  dl_tensor.data = data;
311  shape_ = std::move(shape);
312  dl_tensor.ndim = static_cast<int>(shape_.size());
313  dl_tensor.shape = const_cast<ShapeTuple::index_type*>(shape_.data());
314  dl_tensor.dtype = dtype;
315  dl_tensor.strides = nullptr;
316  dl_tensor.byte_offset = 0;
317  dl_tensor.device = dev;
318  }
323  void SetDeleter(FDeleter deleter) { deleter_ = deleter; }
324 
325  // Expose DecRef and IncRef as public function
326  // NOTE: they are only for developer purposes only.
327  using Object::DecRef;
328  using Object::IncRef;
329 
330  // Information for object protocol.
331  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeNDArray;
332  static constexpr const uint32_t _type_child_slots = 0;
333  static constexpr const uint32_t _type_child_slots_can_overflow = true;
334  static constexpr const char* _type_key = "runtime.NDArray";
336 
337  protected:
338  friend class RPCWrappedFunc;
339  friend class NDArray;
340 };
341 
342 // implementations of inline functions
349 inline size_t GetDataSize(const DLTensor& arr) {
350  size_t size = 1;
351  for (tvm_index_t i = 0; i < arr.ndim; ++i) {
352  size *= static_cast<size_t>(arr.shape[i]);
353  }
354  size *= (arr.dtype.bits * arr.dtype.lanes + 7) / 8;
355  return size;
356 }
357 
363 static inline bool IsContiguous(const DLTensor& arr) {
364  if (arr.strides == nullptr) return true;
365  int64_t expected_stride = 1;
366  for (int32_t i = arr.ndim; i != 0; --i) {
367  int32_t k = i - 1;
368  if (arr.strides[k] != expected_stride) return false;
369  expected_stride *= arr.shape[k];
370  }
371  return true;
372 }
373 
374 inline bool NDArray::IsContiguous() const {
375  return ::tvm::runtime::IsContiguous(get_mutable()->dl_tensor);
376 }
377 
378 inline void NDArray::CopyFrom(const DLTensor* other) {
379  ICHECK(data_ != nullptr);
380  CopyFromTo(other, &(get_mutable()->dl_tensor));
381 }
382 
383 inline void NDArray::CopyFrom(const NDArray& other) {
384  ICHECK(data_ != nullptr);
385  ICHECK(other.data_ != nullptr);
387 }
388 
389 inline void NDArray::CopyTo(DLTensor* other) const {
390  ICHECK(data_ != nullptr);
391  CopyFromTo(&(get_mutable()->dl_tensor), other);
392 }
393 
394 inline void NDArray::CopyTo(const NDArray& other) const {
395  ICHECK(data_ != nullptr);
396  ICHECK(other.data_ != nullptr);
397  CopyFromTo(&(get_mutable()->dl_tensor), &(other.get_mutable()->dl_tensor));
398 }
399 
400 inline NDArray NDArray::CopyTo(const Device& dev) const {
401  ICHECK(data_ != nullptr);
402  const DLTensor* dptr = operator->();
403  NDArray ret = Empty(ShapeTuple(dptr->shape, dptr->shape + dptr->ndim), dptr->dtype, dev);
404  this->CopyTo(ret);
405  return ret;
406 }
407 
408 inline int NDArray::use_count() const { return data_.use_count(); }
409 
410 inline const DLTensor* NDArray::operator->() const { return &(get_mutable()->dl_tensor); }
411 
413  return static_cast<NDArray::Container*>(data_.get());
414 }
415 
417  return GetObjectPtr<Object>(
418  static_cast<NDArray::Container*>(reinterpret_cast<NDArray::ContainerBase*>(handle)));
419 }
420 
422  // NOTE: it is necessary to cast to container then to base
423  // so that the FFI handle uses the ContainerBase address.
424  auto ptr = reinterpret_cast<TVMArrayHandle>(static_cast<NDArray::ContainerBase*>(
425  static_cast<NDArray::Container*>(const_cast<Object*>(nd.get()))));
426  return ptr;
427 }
428 
429 inline void NDArray::FFIDecRef(TVMArrayHandle handle) {
430  static_cast<NDArray::Container*>(reinterpret_cast<NDArray::ContainerBase*>(handle))->DecRef();
431 }
432 
434  return static_cast<NDArray::Container*>(reinterpret_cast<NDArray::ContainerBase*>(handle));
435 }
436 
438 constexpr uint64_t kTVMNDArrayMagic = 0xDD5E40F096B4A13F;
439 
440 inline bool SaveDLTensor(dmlc::Stream* strm, const DLTensor* tensor) {
441  uint64_t header = kTVMNDArrayMagic, reserved = 0;
442  strm->Write(header);
443  strm->Write(reserved);
444  // Always save data as CPU context
445  //
446  // Parameters that get serialized should be in CPU by default.
447  // So even the array's context is GPU, it will be stored as CPU array.
448  // This is used to prevent case when another user loads the parameters
449  // back on machine that do not have GPU or related context.
450  //
451  // We can always do array.CopyTo(target_dev) to get a corresponding
452  // array in the target context.
453  Device cpu_dev;
454  cpu_dev.device_type = kDLCPU;
455  cpu_dev.device_id = 0;
456  strm->Write(cpu_dev);
457  strm->Write(tensor->ndim);
458  strm->Write(tensor->dtype);
459  int ndim = tensor->ndim;
460  strm->WriteArray(tensor->shape, ndim);
461  int type_bytes = (tensor->dtype.bits + 7) / 8;
462  int64_t num_elems = 1;
463  for (int i = 0; i < ndim; ++i) {
464  num_elems *= tensor->shape[i];
465  }
466  int64_t data_byte_size = type_bytes * num_elems;
467  strm->Write(data_byte_size);
468 
469  if (DMLC_IO_NO_ENDIAN_SWAP && tensor->device.device_type == kDLCPU &&
470  tensor->strides == nullptr && tensor->byte_offset == 0) {
471  // quick path
472  strm->Write(tensor->data, data_byte_size);
473  } else {
474  std::vector<uint8_t> bytes(data_byte_size);
475  ICHECK_EQ(
476  TVMArrayCopyToBytes(const_cast<DLTensor*>(tensor), dmlc::BeginPtr(bytes), data_byte_size),
477  0)
478  << TVMGetLastError();
479  if (!DMLC_IO_NO_ENDIAN_SWAP) {
480  dmlc::ByteSwap(dmlc::BeginPtr(bytes), type_bytes, num_elems);
481  }
482  strm->Write(dmlc::BeginPtr(bytes), data_byte_size);
483  }
484  return true;
485 }
486 
487 inline void NDArray::Save(dmlc::Stream* strm) const { SaveDLTensor(strm, operator->()); }
488 
489 inline bool NDArray::Load(dmlc::Stream* strm) {
490  uint64_t header, reserved;
491  ICHECK(strm->Read(&header)) << "Invalid DLTensor file format";
492  ICHECK(strm->Read(&reserved)) << "Invalid DLTensor file format";
493  ICHECK(header == kTVMNDArrayMagic) << "Invalid DLTensor file format";
494  Device dev;
495  int ndim;
496  DLDataType dtype;
497  ICHECK(strm->Read(&dev)) << "Invalid DLTensor file format";
498  ICHECK(strm->Read(&ndim)) << "Invalid DLTensor file format";
499  ICHECK(strm->Read(&dtype)) << "Invalid DLTensor file format";
500  ICHECK_EQ(dev.device_type, kDLCPU) << "Invalid DLTensor device: can only save as CPU tensor";
501  std::vector<int64_t> shape(ndim);
502  if (ndim != 0) {
503  ICHECK(strm->ReadArray(&shape[0], ndim)) << "Invalid DLTensor file format";
504  }
505  NDArray ret = NDArray::Empty(ShapeTuple(shape), dtype, dev);
506  int64_t num_elems = 1;
507  int elem_bytes = (ret->dtype.bits + 7) / 8;
508  for (int i = 0; i < ret->ndim; ++i) {
509  num_elems *= ret->shape[i];
510  }
511  int64_t data_byte_size;
512  ICHECK(strm->Read(&data_byte_size)) << "Invalid DLTensor file format";
513  ICHECK(data_byte_size == num_elems * elem_bytes) << "Invalid DLTensor file format";
514  auto read_ret = strm->Read(ret->data, data_byte_size);
515  // Only check non-empty data
516  if (ndim > 0 && shape[0] != 0) {
517  ICHECK(read_ret) << "Invalid DLTensor file format";
518  }
519  if (!DMLC_IO_NO_ENDIAN_SWAP) {
520  dmlc::ByteSwap(ret->data, elem_bytes, num_elems);
521  }
522  *this = ret;
523  return true;
524 }
525 
526 } // namespace runtime
527 } // namespace tvm
528 
529 namespace std {
530 template <>
531 struct hash<tvm::Device> {
532  std::size_t operator()(const tvm::Device& dev) const {
533  return ((dev.device_id << 8) | dev.device_type);
534  }
535 };
536 
537 template <>
538 struct equal_to<tvm::Device> {
539  bool operator()(const tvm::Device& lhs, const tvm::Device& rhs) const {
540  return (lhs.device_type == rhs.device_type && lhs.device_id == rhs.device_id);
541  }
542 };
543 } // namespace std
544 
545 #endif // TVM_RUNTIME_NDARRAY_H_
The container base structure contains all the fields except for the Object header.
Definition: ndarray.h:264
DLManagedTensor * ToDLPack() const
Create a reference view of NDArray that represents as DLManagedTensor.
Return Value container, Unlike TVMArgValue, which only holds reference and do not delete the underlyi...
Definition: packed_func.h:799
static void FFIDecRef(TVMArrayHandle handle)
DecRef resource managed by an FFI array handle.
Definition: ndarray.h:429
runtime::DataType DataType() const
A custom smart pointer for Object.
Definition: object.h:358
Runtime Optional container types.
bool Load(dmlc::Stream *stream)
Load NDArray from stream.
Definition: ndarray.h:489
Runtime String container types.
Internal base class to handle conversion to POD values.
Definition: packed_func.h:541
void CopyFrom(const DLTensor *other)
Copy data content from another array.
Definition: ndarray.h:378
runtime implementation for LibTorch/TorchScript.
Definition: analyzer.h:36
static NDArray NewFromDLTensor(DLTensor *dl_tensor, const Device &dev)
Create new NDArray, data is copied from DLTensor.
DLTensor * TVMArrayHandle
the array handle
Definition: c_runtime_api.h:138
Serializer extension to support TVM data types Include this file to enable serialization of DLDataTyp...
NDArray CreateView(ShapeTuple shape, DLDataType dtype)
Create a NDArray that shares the data memory with the current one.
void IncRef()
developer function, increases reference counter.
Definition: object.h:799
Definition: loop_state.h:456
int TVMArrayCopyToBytes(TVMArrayHandle handle, void *data, size_t nbytes)
Copy array data to CPU byte array.
void CopyTo(DLTensor *other) const
Copy data content into another array.
Definition: ndarray.h:389
static NDArray Empty(ShapeTuple shape, DLDataType dtype, Device dev, Optional< String > mem_scope=NullOpt)
Create an empty NDArray.
base class of all object containers.
Definition: object.h:167
bool IsContiguous() const
Definition: ndarray.h:374
Object * TVMArrayHandleToObjectHandle(TVMArrayHandle handle)
Definition: ndarray.h:433
const char * TVMGetLastError(void)
return str message of the last error all function in this file will return 0 when success and nonzero...
void reset()
reset the content of NDArray to be nullptr
Managed NDArray. The array is backed by reference counted blocks.
Definition: ndarray.h:59
void * TVMStreamHandle
The stream that is specific to device can be NULL, which indicates the default one.
Definition: c_runtime_api.h:172
void DecRef()
developer function, decrease reference counter.
Definition: object.h:801
static uint32_t RuntimeTypeIndex()
Definition: object.h:225
static void CopyFromTo(const DLTensor *from, DLTensor *to, TVMStreamHandle stream=nullptr)
Function to copy data from one array to another.
int use_count() const
Definition: ndarray.h:408
void Save(dmlc::Stream *stream) const
Save NDArray to stream.
Definition: ndarray.h:487
static bool AbilityOfZeroCopyForDLTensor(DLTensor *tensor, const Device &dev)
Check conditions for construction NDArray over DLTensor without copying. There are three conditions t...
const DLTensor * operator->() const
Definition: ndarray.h:410
static ObjectPtr< Object > FFIDataFromHandle(TVMArrayHandle handle)
Construct NDArray&#39;s Data field from array handle in FFI.
Definition: ndarray.h:416
NDArray(ObjectPtr< Object > data)
constructor.
Definition: ndarray.h:73
Runtime primitive data type.
Definition: data_type.h:41
ShapeTuple Shape() const
Container * get_mutable() const
Get mutable internal container pointer.
Definition: ndarray.h:412
Object container class that backs NDArray.
Definition: ndarray.h:294
Container(void *data, ShapeTuple shape, DLDataType dtype, Device dev)
Definition: ndarray.h:307
ObjectPtr< Object > data_
Internal pointer that backs the reference.
Definition: object.h:574
DLTensor dl_tensor
The corresponding dl_tensor field.
Definition: ndarray.h:272
void SetDeleter(FDeleter deleter)
Set the deleter field.
Definition: ndarray.h:323
Tensor shape(const Tensor &src, DataType dtype, const std::string name="T_shape", const std::string tag=kInjective)
Get the shape of input tensor.
Definition: transform.h:1758
int64_t tvm_index_t
type of array index.
Definition: c_runtime_api.h:81
DLDevice Device
Definition: ndarray.h:43
const Object * get() const
Definition: object.h:546
Base class of all object reference.
Definition: object.h:511
static NDArray FromExternalDLTensor(const DLTensor &dl_tensor)
Create a NDArray backed by an external DLTensor without memory copying.
Runtime ShapeTuple container types.
A managed object in the TVM runtime.
static TVMArrayHandle FFIGetHandle(const ObjectRef &nd)
Get FFI Array handle from ndarray.
Definition: ndarray.h:421
Container()
default constructor
Definition: ndarray.h:297
constexpr uint64_t kTVMNDArrayMagic
Magic number for NDArray file.
Definition: ndarray.h:438
NDArray()
default constructor
Definition: ndarray.h:68
ShapeTupleObj::index_type index_type
The type of shape index element.
Definition: shape_tuple.h:84
void CopyFromBytes(const void *data, size_t nbytes)
Copy data content from a byte buffer.
PrimExpr ret(PrimExpr value, Span span=Span())
Return the value.
Optional container that to represent to a Nullable variant of T.
Definition: optional.h:51
bool SaveDLTensor(dmlc::Stream *strm, const DLTensor *tensor)
Save a DLTensor to stream.
Definition: ndarray.h:440
static NDArray FromDLPack(DLManagedTensor *tensor)
Create a NDArray backed by a dlpack tensor.
Definition: packed_func.h:1514
constexpr runtime::NullOptType NullOpt
Definition: optional.h:160
void CopyToBytes(void *data, size_t nbytes) const
Copy data content into another array.
constexpr DLDeviceType kNullDeviceType
Definition: ndarray.h:48
#define TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType)
helper macro to declare a base object type that can be inherited.
Definition: object.h:648
constexpr DLDeviceType kInvalidDeviceType
Definition: ndarray.h:51
ShapeTuple shape_
The shape container, can be used used for shape data.
Definition: ndarray.h:287
size_t GetDataSize(const DLTensor &arr)
return the size of data the DLTensor hold, in term of number of bytes
Definition: ndarray.h:349
Reference to shape tuple objects.
Definition: shape_tuple.h:81
runtime::NDArray.
Definition: object.h:64