diff --git a/cmake/modules/Hexagon.cmake b/cmake/modules/Hexagon.cmake index 1491a4558611..224c505ab958 100644 --- a/cmake/modules/Hexagon.cmake +++ b/cmake/modules/Hexagon.cmake @@ -53,18 +53,22 @@ if(BUILD_FOR_HEXAGON) include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_QURT_INCLUDES}) endif() -if(USE_HEXAGON_LAUNCHER STREQUAL "ON") - set(USE_HEXAGON_DEVICE "${PICK_SIM}") -else() - if(USE_HEXAGON_DEVICE STREQUAL "OFF") - list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc) - return() - elseif(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND - NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}") - set(ERROR_MSG - "USE_HEXAGON_DEVICE must be one of [${PICK_NONE}|${PICK_SIM}|${PICK_HW}]") - message(SEND_ERROR "${ERROR_MSG}") - return() +# Don't run these checks when compiling Hexagon device code, +# e.g. when compiling the TVM runtime for Hexagon. +if (NOT BUILD_FOR_HEXAGON) + if(USE_HEXAGON_LAUNCHER STREQUAL "ON") + set(USE_HEXAGON_DEVICE "${PICK_SIM}") + else() + if(USE_HEXAGON_DEVICE STREQUAL "OFF") + list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc) + return() + elseif(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND + NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}") + set(ERROR_MSG + "USE_HEXAGON_DEVICE must be one of [${PICK_NONE}|${PICK_SIM}|${PICK_HW}]") + message(SEND_ERROR "${ERROR_MSG}") + return() + endif() endif() endif() diff --git a/src/runtime/hexagon/hexagon/hexagon_buffer.cc b/src/runtime/hexagon/hexagon/hexagon_buffer.cc new file mode 100644 index 000000000000..0760bab6c582 --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_buffer.cc @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "hexagon_buffer.h" + +#include + +#include +#include + +#include "hexagon_common.h" + +namespace tvm { +namespace runtime { +namespace hexagon { + +static size_t GetDataAlignment(const DLDataType dtype) { + size_t align = (dtype.bits / 8) * dtype.lanes; + if (align < kAllocAlignment) return kAllocAlignment; + return align; +} + +HexagonBuffer::HexagonBuffer(int ndim, const int64_t* shape, DLDataType dtype, + Optional scope) { + ICHECK_LE(ndim, 1) << "Hexagon currently only supports flat allocations " + << "and arrays of flat allocations."; + + size_t alignment = GetDataAlignment(dtype); + // TODO(csullivan): Extend to support arrays of allocations. + // Move assignment from r-value constructed flat allocation. + *this = HexagonBuffer(shape[0] * (dtype.bits / 8) * dtype.lanes, alignment, scope); +} + +HexagonBuffer::HexagonBuffer(size_t nbytes, size_t alignment, Optional scope) { + void* ptr = nullptr; + int ret = posix_memalign(&ptr, alignment, nbytes); + if (ret != 0) { + throw std::bad_alloc(); + } + allocations_.push_back(ptr); + SetStorageScope(scope); +} + +HexagonBuffer::HexagonBuffer(void* data, Optional scope) : managed_{false} { + SetStorageScope(scope); + allocations_.push_back(data); +} + +HexagonBuffer::~HexagonBuffer() { + if (managed_) { + for (auto& ptr : allocations_) { + free(ptr); + } + } +} + +HexagonBuffer::HexagonBuffer(HexagonBuffer&& other) + : allocations_(other.allocations_), + managed_(other.managed_), + storage_scope_(other.storage_scope_) { + other.allocations_.clear(); + other.managed_ = false; + other.storage_scope_ = StorageScope::kDDR; +} + +HexagonBuffer& HexagonBuffer::operator=(HexagonBuffer&& other) { + std::swap(allocations_, other.allocations_); + std::swap(managed_, other.managed_); + std::swap(storage_scope_, other.storage_scope_); + return *this; +} + +void* HexagonBuffer::GetPointer() { + if (!allocations_.size()) { + return nullptr; + } + return (allocations_.size() > 1) ? allocations_.data() : allocations_[0]; +} + +HexagonBuffer::StorageScope HexagonBuffer::GetStorageScope() const { return storage_scope_; } + +void HexagonBuffer::SetStorageScope(Optional scope) { + if (!scope.defined()) { + storage_scope_ = StorageScope::kDDR; + } else { + if (scope.value() == "global") { + storage_scope_ = StorageScope::kDDR; + } else if (scope.value() == "global.vtcm") { + storage_scope_ = StorageScope::kVTCM; + } else { + CHECK(false) << "Encountered unknown HexagonBuffer storage scope: " + << std::string(scope.value()); + } + } +} + +HexagonBuffer* IsHexagonBuffer(DLTensor* tensor) { + if (TVMDeviceExtType(tensor->device.device_type) == kDLHexagon) { + return static_cast(tensor->data); + } + return nullptr; +} + +} // namespace hexagon +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/hexagon/hexagon/hexagon_buffer.h b/src/runtime/hexagon/hexagon/hexagon_buffer.h new file mode 100644 index 000000000000..c62cee66b0d8 --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_buffer.h @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_ +#define TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_ + +#include +#include +#include +#include +#include + +#include + +namespace tvm { +namespace runtime { +namespace hexagon { + +class HexagonBuffer { + public: + /* \brief Allocate memory within hexagon accessible memory + * scopes. + * + * \param ndim The number of dimensions of physical storage + * to allocate. + * + * \param shape The shape of the ndarray for which to allocate + * physical storage. + * + * \param dtype The data type of the physical storage. + * + * \param scope Optional storage scope indicating the memory + * space in which to allocate. Defaults to global system + * memory (DDR). + */ + HexagonBuffer(int ndim, const int64_t* shape, DLDataType dtype, Optional scope); + + /* \brief Allocate memory within hexagon accessible memory + * scopes. + * + * \param nbytes The number of bytes of flat physical storage + * to allocate. + * + * \param alignment The byte alignment to be used when allocating. + * + * \param scope Optional storage scope indicating the memory + * space in which to allocate. Defaults to global system + * memory (DDR). + */ + HexagonBuffer(size_t nbytes, size_t alignment, Optional scope); + + /* \brief Construct a hexagon buffer from externally allocated storage. + * + * \param data The externally allocated storage. + * + * \param scope Optional storage scope indicating the memory + * space in the external allocation belongs. Assumes global system + * memory if not provided. + */ + explicit HexagonBuffer(void* data, Optional scope = Optional()); + + //! \brief Destruction deallocates the underlying allocations. + ~HexagonBuffer(); + + //! \brief Prevent copy construction of HexagonBuffers. + HexagonBuffer(const HexagonBuffer&) = delete; + + //! \brief Prevent copy assignment with HexagonBuffers. + HexagonBuffer& operator=(const HexagonBuffer&) = delete; + + //! \brief Allow move construction. + HexagonBuffer(HexagonBuffer&&); + + //! \brief Allow move assignment. + HexagonBuffer& operator=(HexagonBuffer&&); + + //! \brief Return pointer to allocation or allocations. + void* GetPointer(); + + //! \brief Memory scopes managed by a Hexagon Buffer. + enum class StorageScope { + //! \brief System DDR corresponding to global storage. + kDDR, + /*! \brief Vector tightly coupled memory corresponding to + * global.vtcm storage. + */ + kVTCM, + }; + + //! \brief Return storage scope of underlying allocation. + StorageScope GetStorageScope() const; + + private: + //! \brief Assign a storage scope to the buffer. + void SetStorageScope(Optional scope); + /*! \brief Array of allocations required by the buffer. + * + * For a 1d (flat) storage, a single contiguous allocation will + * result. For 2d storage, (count, nbytes) = shape, which will + * result in `count` discrete allocations. + */ + std::vector allocations_; + /*! \brief Whether the allocation(s) present are managed + * and should be deallocated upon destruction. + */ + bool managed_{true}; + /*! \brief The underlying storage type in which the allocation + * resides. + */ + StorageScope storage_scope_; +}; + +HexagonBuffer* IsHexagonBuffer(DLTensor* tensor); + +} // namespace hexagon +} // namespace runtime +} // namespace tvm + +#endif // TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_ diff --git a/src/runtime/hexagon/hexagon/hexagon_common.cc b/src/runtime/hexagon/hexagon/hexagon_common.cc new file mode 100644 index 000000000000..260b105ac43a --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_common.cc @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file hexagon_common.cc + */ + +#include "hexagon_common.h" + +#include +#include + +#include +#include +#include +#include + +#include "hexagon_buffer.h" + +namespace tvm { +namespace runtime { +namespace hexagon { + +void HexagonLookupLinkedParam(TVMArgs args, TVMRetValue* rv) { + Module mod = args[0]; + int64_t storage_id = args[1]; + DLTensor* template_tensor = args[2]; + Device dev = args[3]; + auto lookup_linked_param = mod.GetFunction(::tvm::runtime::symbol::tvm_lookup_linked_param, true); + if (lookup_linked_param == nullptr) { + *rv = nullptr; + return; + } + + TVMRetValue opaque_handle = lookup_linked_param(storage_id); + if (opaque_handle.type_code() == kTVMNullptr) { + *rv = nullptr; + return; + } + + std::vector shape_vec{template_tensor->shape, + template_tensor->shape + template_tensor->ndim}; + + auto* param_buffer = new HexagonBuffer(static_cast(opaque_handle)); + auto* container = new NDArray::Container(static_cast(param_buffer), shape_vec, + template_tensor->dtype, dev); + container->SetDeleter([](Object* container) { + // The NDArray::Container needs to be deleted + // along with the HexagonBuffer wrapper. However the + // buffer's data points to global const memory and + // so should not be deleted. + auto* ptr = static_cast(container); + delete static_cast(ptr->dl_tensor.data); + delete ptr; + }); + *rv = NDArray(GetObjectPtr(container)); +} + +PackedFunc WrapPackedFunc(TVMBackendPackedCFunc faddr, const ObjectPtr& sptr_to_self) { + return PackedFunc([faddr, sptr_to_self](TVMArgs args, TVMRetValue* rv) { + TVMValue ret_value; + int ret_type_code = kTVMNullptr; + + TVMValue* arg_values = const_cast(args.values); + std::vector> buffer_args; + for (size_t i = 0; i < args.num_args; i++) { + if (args.type_codes[i] == kTVMDLTensorHandle) { + DLTensor* tensor = static_cast(arg_values[i].v_handle); + buffer_args.emplace_back(i, static_cast(tensor->data)); + tensor->data = buffer_args.back().second->GetPointer(); + } + } + int ret = (*faddr)(const_cast(args.values), const_cast(args.type_codes), + args.num_args, &ret_value, &ret_type_code, nullptr); + ICHECK_EQ(ret, 0) << TVMGetLastError(); + + for (auto& arg : buffer_args) { + DLTensor* tensor = static_cast(arg_values[arg.first].v_handle); + tensor->data = arg.second; + } + + if (ret_type_code != kTVMNullptr) { + *rv = TVMRetValue::MoveFromCHost(ret_value, ret_type_code); + } + }); +} +} // namespace hexagon + +namespace { +std::vector SplitString(const std::string& str, char delim) { + std::vector lines; + auto ss = std::stringstream{str}; + for (std::string line; std::getline(ss, line, delim);) { + lines.push_back(line); + } + return lines; +} +void HexagonLog(const std::string& file, int lineno, const std::string& message) { + HEXAGON_PRINT(ALWAYS, "%s:%d:", file.c_str(), lineno); + std::vector err_lines = SplitString(message, '\n'); + for (auto& line : err_lines) { + HEXAGON_PRINT(ALWAYS, "%s", line.c_str()); + } +} +} // namespace + +namespace detail { +void LogFatalImpl(const std::string& file, int lineno, const std::string& message) { + HexagonLog(file, lineno, message); + throw InternalError(file, lineno, message); +} +void LogMessageImpl(const std::string& file, int lineno, const std::string& message) { + HexagonLog(file, lineno, message); +} +} // namespace detail + +TVM_REGISTER_GLOBAL("tvm.runtime.hexagon.lookup_linked_params") + .set_body(hexagon::HexagonLookupLinkedParam); +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/hexagon/hexagon/hexagon_common.h b/src/runtime/hexagon/hexagon/hexagon_common.h new file mode 100644 index 000000000000..a84ea4e20245 --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_common.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file hexagon_utils.h + */ +#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_COMMON_H_ +#define TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_COMMON_H_ + +#include +#include + +#if defined(__hexagon__) +#include +#define HEXAGON_PRINT(level, ...) FARF(level, __VA_ARGS__) +#else +#include +#define HEXAGON_PRINT(level, ...) printf(__VA_ARGS__) +#endif + +#define HEXAGON_SAFE_CALL(api_call) \ + do { \ + int result = api_call; \ + if (result != 0) { \ + HEXAGON_PRINT(ERROR, "ERROR: " #api_call " failed with error %d.", result); \ + } \ + } while (0) + +namespace tvm { +namespace runtime { +namespace hexagon { + +/*! \brief Unpack HexagonBuffers in packed functions + * prior to invoking. + * \param faddr The function address. + * \param mptr The module pointer node. + * \return A packed function wrapping the requested function. + */ +PackedFunc WrapPackedFunc(TVMBackendPackedCFunc faddr, const ObjectPtr& mptr); +} // namespace hexagon +} // namespace runtime +} // namespace tvm +inline bool IsHexagonDevice(DLDevice dev) { + return TVMDeviceExtType(dev.device_type) == kDLHexagon; +} + +#endif // TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_COMMON_H_ diff --git a/src/runtime/hexagon/hexagon/hexagon_device_api_v2.cc b/src/runtime/hexagon/hexagon/hexagon_device_api_v2.cc new file mode 100644 index 000000000000..9c1f6ebd7d70 --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_device_api_v2.cc @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file hexagon_device_api_v2.cc + */ + +#include "hexagon_device_api_v2.h" + +#include +#include +#include +#include + +#include +#include + +#include "../../workspace_pool.h" +#include "hexagon_buffer.h" +#include "hexagon_common.h" + +namespace tvm { +namespace runtime { +namespace hexagon { + +HexagonDeviceAPIv2* HexagonDeviceAPIv2::Global() { + static auto* inst = new HexagonDeviceAPIv2(); + return inst; +} + +void HexagonDeviceAPIv2::GetAttr(Device dev, DeviceAttrKind kind, TVMRetValue* rv) { + if (kind == kExist) { + *rv = 1; + } +} + +void* HexagonDeviceAPIv2::AllocDataSpace(Device dev, int ndim, const int64_t* shape, + DLDataType dtype, Optional mem_scope) { + return new HexagonBuffer(ndim, shape, dtype, mem_scope.defined() ? mem_scope : String("global")); +} + +void* HexagonDeviceAPIv2::AllocDataSpace(Device dev, size_t nbytes, size_t alignment, + DLDataType type_hint) { + return new HexagonBuffer(nbytes, alignment, String("global")); +} + +void HexagonDeviceAPIv2::FreeDataSpace(Device dev, void* ptr) { + auto* pbuf = static_cast(ptr); + delete pbuf; +} + +struct HexagonWorkspacePool : public WorkspacePool { + HexagonWorkspacePool() : WorkspacePool(kDLCPU, HexagonDeviceAPIv2::Global()) {} +}; + +void* HexagonDeviceAPIv2::AllocWorkspace(Device dev, size_t size, DLDataType type_hint) { + auto* buffer = static_cast( + dmlc::ThreadLocalStore::Get()->AllocWorkspace(dev, size)); + void* ptr = buffer->GetPointer(); + workspace_allocations_.insert({ptr, buffer}); + return ptr; +} + +void HexagonDeviceAPIv2::FreeWorkspace(Device dev, void* data) { + auto it = workspace_allocations_.find(data); + ICHECK(it != workspace_allocations_.end()) + << "Attempt made to free unknown or already freed workspace allocation"; + dmlc::ThreadLocalStore::Get()->FreeWorkspace(dev, it->second); + workspace_allocations_.erase(it); +} + +void HexagonDeviceAPIv2::CopyDataFromTo(DLTensor* from, DLTensor* to, TVMStreamHandle stream) { + if (IsHexagonDevice(from->device) && IsHexagonDevice(to->device)) { + HexagonBuffer* buffer_src = static_cast(from->data); + HexagonBuffer* buffer_dst = static_cast(to->data); + // Check storage scopes + if (buffer_src->GetStorageScope() == HexagonBuffer::StorageScope::kDDR && + buffer_dst->GetStorageScope() == HexagonBuffer::StorageScope::kDDR) { + memcpy(static_cast(buffer_dst->GetPointer()) + to->byte_offset, + static_cast(buffer_src->GetPointer()) + from->byte_offset, + GetDataSize(*from)); + } else { + ICHECK(false) << "Currently only copying between DDR storage is supported."; + } + } else if (IsHexagonDevice(from->device) && to->device.device_type == kDLCPU) { + HexagonBuffer* buffer_src = static_cast(from->data); + memcpy(static_cast(to->data) + to->byte_offset, + static_cast(buffer_src->GetPointer()) + from->byte_offset, + GetDataSize(*from)); + } else if (from->device.device_type == kDLCPU && IsHexagonDevice(to->device)) { + HexagonBuffer* buffer_dst = static_cast(to->data); + memcpy(static_cast(buffer_dst->GetPointer()) + to->byte_offset, + static_cast(from->data) + from->byte_offset, GetDataSize(*from)); + } else { + CHECK(false) + << "Expect copy between DLTensor devices of types kDLHexagon and kDLCPU (external) only."; + } +} + +void HexagonDeviceAPIv2::CopyDataFromTo(const void* from, size_t from_offset, void* to, + size_t to_offset, size_t size, Device dev_from, + Device dev_to, DLDataType type_hint, + TVMStreamHandle stream) { + memcpy(static_cast(to) + to_offset, static_cast(from) + from_offset, size); +} + +TVM_REGISTER_GLOBAL("device_api.hexagon.v2").set_body([](TVMArgs args, TVMRetValue* rv) { + DeviceAPI* ptr = HexagonDeviceAPIv2::Global(); + *rv = static_cast(ptr); +}); + +} // namespace hexagon +} // namespace runtime +} // namespace tvm diff --git a/src/runtime/hexagon/hexagon/hexagon_device_api_v2.h b/src/runtime/hexagon/hexagon/hexagon_device_api_v2.h new file mode 100644 index 000000000000..3d866307f17c --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_device_api_v2.h @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_DEVICE_API_V2_H_ +#define TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_DEVICE_API_V2_H_ + +#include + +#include + +namespace tvm { +namespace runtime { +namespace hexagon { + +class HexagonBuffer; + +/*! + * \brief Hexagon Device API that is compiled and run on Hexagon. + */ +class HexagonDeviceAPIv2 final : public DeviceAPI { + public: + //! \brief Retrieve the global singleton instance of the HexagonDeviceAPIv2. + static HexagonDeviceAPIv2* Global(); + + //! \brief Constructor + HexagonDeviceAPIv2() {} + + //! \brief Destructor + ~HexagonDeviceAPIv2() {} + + /*! \brief Currently unimplemented interface to specify the active + * Hexagon device. + */ + void SetDevice(Device dev) final{}; + + //! \brief Return the queried Hexagon device attribute. + void GetAttr(Device dev, DeviceAttrKind kind, TVMRetValue* rv) final; + + //! \brief Currently unimplemented interface to synchronize a device stream. + void StreamSync(Device dev, TVMStreamHandle stream) final {} + + //! \note Standard memory allocation methods of the DeviceAPI interface. + //! \brief Allocate a flat allocation of global memory wrapped in a HexagonBuffer. + void* AllocDataSpace(Device dev, size_t nbytes, size_t alignment, DLDataType type_hint) final; + + //! \brief Free the allocated HexagonBuffer. + void FreeDataSpace(Device dev, void* ptr) final; + + /*! \brief Request a dynamically allocated HexagonBuffer from a workspace pool. + * \returns The underlying allocation pointer. + */ + void* AllocWorkspace(Device dev, size_t size, DLDataType type_hint) final; + + //! Dereference workspace pool and erase from tracked workspace_allocations_. + void FreeWorkspace(Device dev, void* data) final; + + /*! + * \brief Allocate an Nd data space on device with memory scope support. + * \param dev The device to perform the operation. + * \param ndim The number of dimensions of allocated tensor. + * \param shape The shape of allocated tensor. + * \param dtype The element type. + * \param mem_scope The memory scope of the allocated tensor. + * \return The allocated HexagonBuffer pointer. + */ + void* AllocDataSpace(Device dev, int ndim, const int64_t* shape, DLDataType dtype, + Optional mem_scope) final; + + /*! + * \brief Copy data from one storage to another. + * \note This API is designed to support special memory with shape dependent layout. + * DLTensor's are passed with shape information to support these cases. + * \param from The source array. + * \param to The target array. + * \param stream Optional stream object. + */ + void CopyDataFromTo(DLTensor* from, DLTensor* to, TVMStreamHandle stream) final; + + protected: + //! Standard Device API interface to copy data from one storage to another. + void CopyDataFromTo(const void* from, size_t from_offset, void* to, size_t to_offset, size_t size, + Device dev_from, Device dev_to, DLDataType type_hint, + TVMStreamHandle stream) final; + + private: + //! Lookup table for the HexagonBuffer managing a workspace allocation. + std::unordered_map workspace_allocations_; +}; +} // namespace hexagon +} // namespace runtime +} // namespace tvm +#endif // TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_DEVICE_API_V2_H_ diff --git a/src/runtime/hexagon/hexagon/hexagon_module.cc b/src/runtime/hexagon/hexagon/hexagon_module.cc new file mode 100644 index 000000000000..5fc6d71e00c9 --- /dev/null +++ b/src/runtime/hexagon/hexagon/hexagon_module.cc @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/*! + * \file hexagon_module.cc + * \brief The HexagonLibraryModuleNode + */ +#include "../hexagon_module.h" + +#include +#include +#include + +#include +#include +#include + +#include "../../dso_library.h" +#include "hexagon_buffer.h" +#include "hexagon_common.h" + +namespace tvm { +namespace runtime { + +Module HexagonModuleCreate(std::string data, std::string fmt, + std::unordered_map fmap, std::string asm_str, + std::string obj_str, std::string ir_str, std::string bc_str, + const std::set& packed_c_abi) { + CHECK(fmt == "so") << "Invalid format provided when constructing Hexagon runtime module: " << fmt + << ". Valid formats are: 'so'."; + auto n = make_object(); + n->Init(data); + return CreateModuleFromLibrary(n, hexagon::WrapPackedFunc); +} + +TVM_REGISTER_GLOBAL("runtime.module.loadfile_hexagon").set_body([](TVMArgs args, TVMRetValue* rv) { + auto n = make_object(); + n->Init(args[0]); + *rv = CreateModuleFromLibrary(n, hexagon::WrapPackedFunc); +}); +} // namespace runtime +} // namespace tvm