Unverified Commit 02d3a59b by Krzysztof Parzyszek Committed by GitHub

[RUNTIME] Initial implementation of Hexagon runtime support (#5252)

* [RUNTIME] Initial implementation of Hexagon runtime support

This is only the TVM runtime. The FastRPC libraries, simulator driver,
etc. will be provided in subsequent commits.

* Fix pylint complaints

* Fix some more pylint complaints

* Add link to the Hexagon SDK website

* Extract VTCM marker into a common variable

* Implement device->device memory copy

* Disable unsigned PDs by default

* Ensure that --hvx_length is present in sim_args if HVX is enabled

* Remove the line about clang from README.md

Apparently things work with libstdc++.

* Mention to set USE_RPC=OFF when building libtvm_runtime.so for Hexagon

* Remember to use codegen_hvx in validate_hvx_length

* Add a line about minimum version of LLVM
parent f0f03647
......@@ -28,6 +28,8 @@ tvm_option(USE_OPENGL "Build with OpenGL" OFF)
tvm_option(USE_METAL "Build with Metal" OFF)
tvm_option(USE_ROCM "Build with ROCM" OFF)
tvm_option(ROCM_PATH "The path to rocm" /opt/rocm)
tvm_option(USE_HEXAGON_DEVICE "Build with Hexagon device support in TVM runtime" OFF)
tvm_option(USE_HEXAGON_SDK "Path to the Hexagon SDK root (required for Hexagon support in TVM runtime or for building TVM runtime for Hexagon)" /path/to/sdk)
tvm_option(USE_RPC "Build with RPC" ON)
tvm_option(USE_THREADS "Build with thread support" ON)
tvm_option(USE_LLVM "Build with LLVM, can be set to specific llvm-config path" OFF)
......@@ -78,7 +80,7 @@ include_directories(${PICOJSON_PATH})
# initial variables
set(TVM_LINKER_LIBS "")
set(TVM_RUNTIME_LINKER_LIBS ${CMAKE_DL_LIBS})
set(TVM_RUNTIME_LINKER_LIBS "")
# Generic compilation options
if(MSVC)
......@@ -118,8 +120,33 @@ else(MSVC)
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
set(CMAKE_CXX_FLAGS "-faligned-new ${CMAKE_CXX_FLAGS}")
endif()
# Detect if we're compiling for Hexagon.
set(TEST_FOR_HEXAGON_CXX
"#ifndef __hexagon__"
"#error"
"#endif"
"int main() {}"
# Define _start_main to avoid linking errors with -fPIC.
"extern \"C\" void _start_main() {}")
set(TEST_FOR_HEXAGON_DIR
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
set(TEST_FOR_HEXAGON_FILE "${TEST_FOR_HEXAGON_DIR}/test_for_hexagon.cc")
string(REPLACE ";" "\n" TEST_FOR_HEXAGON_CXX_TEXT "${TEST_FOR_HEXAGON_CXX}")
file(WRITE "${TEST_FOR_HEXAGON_FILE}" "${TEST_FOR_HEXAGON_CXX_TEXT}")
try_compile(BUILD_FOR_HEXAGON "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}"
"${TEST_FOR_HEXAGON_FILE}")
file(REMOVE "${TEST_FOR_HEXAGON_FILE}")
if(BUILD_FOR_HEXAGON)
message(STATUS "Building for Hexagon")
endif()
endif(MSVC)
# Hexagon has dlopen built into QuRT (no need for static library).
if(NOT BUILD_FOR_HEXAGON)
string(APPEND TVM_RUNTIME_LINKER_LIBS ${CMAKE_DL_LIBS})
endif()
# add source group
FILE(GLOB_RECURSE GROUP_SOURCE "src/*.cc")
FILE(GLOB_RECURSE GROUP_INCLUDE "src/*.h" "include/*.h")
......@@ -177,6 +204,13 @@ if(USE_VM_PROFILER)
list(APPEND COMPILER_SRCS ${BACKEND_VM_PROFILER_SRCS})
endif(USE_VM_PROFILER)
if(BUILD_FOR_HEXAGON)
# Add file implementing posix_memalign.
list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon_posix.cc)
add_definitions(-D_MACH_I32=int)
endif()
file(GLOB DATATYPE_SRCS src/target/datatype/*.cc)
list(APPEND COMPILER_SRCS ${DATATYPE_SRCS})
......@@ -242,6 +276,7 @@ endif(USE_EXAMPLE_EXT_RUNTIME)
# Module rules
include(cmake/modules/VTA.cmake)
include(cmake/modules/CUDA.cmake)
include(cmake/modules/Hexagon.cmake)
include(cmake/modules/OpenCL.cmake)
include(cmake/modules/OpenGL.cmake)
include(cmake/modules/OpenMP.cmake)
......@@ -283,7 +318,19 @@ else()
set_target_properties(tvm PROPERTIES COMPILE_DEFINITIONS "NDEBUG")
endif(USE_RELAY_DEBUG)
if(USE_THREADS)
if(BUILD_FOR_HEXAGON)
# Wrap pthread_create to allow setting custom stack size.
set_target_properties(tvm_runtime PROPERTIES LINK_FLAGS
"-Wl,--wrap=pthread_create")
target_include_directories(tvm_runtime
PUBLIC "${USE_HEXAGON_SDK}/libs/common/qurt/ADSPv62MP/include/posix"
PUBLIC "${USE_HEXAGON_SDK}/libs/common/qurt/ADSPv62MP/include/qurt"
PUBLIC "${USE_HEXAGON_SDK}/incs"
PUBLIC "${USE_HEXAGON_SDK}/incs/stddef")
endif()
if(USE_THREADS AND NOT BUILD_FOR_HEXAGON)
message(STATUS "Build with thread support...")
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
......@@ -291,7 +338,7 @@ if(USE_THREADS)
target_link_libraries(tvm Threads::Threads)
target_link_libraries(tvm_topi Threads::Threads)
target_link_libraries(tvm_runtime Threads::Threads)
endif(USE_THREADS)
endif()
target_link_libraries(tvm ${TVM_LINKER_LIBS} ${TVM_RUNTIME_LINKER_LIBS})
target_link_libraries(tvm_topi tvm ${TVM_LINKER_LIBS} ${TVM_RUNTIME_LINKER_LIBS})
......
......@@ -208,3 +208,6 @@ set(USE_THRUST OFF)
# Whether to build the TensorFlow TVMDSOOp module
set(USE_TF_TVMDSOOP OFF)
# Whether to use hexagon device
set(USE_HEXAGON_DEVICE OFF)
set(USE_HEXAGON_SDK /path/to/sdk)
# 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.
set(PICK_SIM "sim")
set(PICK_HW "target")
set(PICK_NONE "OFF")
function(find_hexagon_toolchain)
if (NOT "${USE_HEXAGON_TOOLCHAIN}" STREQUAL "")
set(TRY_PATH "${USE_HEXAGON_TOOLCHAIN}")
else()
set(TRY_PATH "${USE_HEXAGON_SDK}")
endif()
message(STATUS "Looking for Hexagon toolchain in ${TRY_PATH}")
file(GLOB_RECURSE HEXAGON_CLANG "${TRY_PATH}/*/hexagon-clang++")
if(HEXAGON_CLANG)
# The path is ${HEXAGON_TOOLCHAIN}/bin/hexagon-clang++.
get_filename_component(HEXAGON_TMP0 "${HEXAGON_CLANG}" DIRECTORY)
get_filename_component(HEXAGON_TMP1 "${HEXAGON_TMP0}" DIRECTORY)
set(HEXAGON_TOOLCHAIN "${HEXAGON_TMP1}" CACHE PATH
"Path to the Hexagon toolchain")
else(HEXAGON_CLANG)
message(SEND_ERROR "Cannot find Hexagon toolchain in ${TRY_PATH}")
endif()
endfunction()
function(find_hexagon_sdk_root)
message(STATUS "Checking Hexagon SDK root: ${USE_HEXAGON_SDK}")
file(GLOB_RECURSE HEXAGON_AEESTDDEF "${USE_HEXAGON_SDK}/*/AEEStdDef.h")
if(HEXAGON_AEESTDDEF)
# The path is ${HEXAGON_SDK_ROOT}/incs/stddef/AEEStdDef.h.
get_filename_component(HEXAGON_TMP0 "${HEXAGON_AEESTDDEF}" DIRECTORY)
get_filename_component(HEXAGON_TMP1 "${HEXAGON_TMP0}" DIRECTORY)
get_filename_component(HEXAGON_TMP2 "${HEXAGON_TMP1}" DIRECTORY)
set(HEXAGON_SDK_ROOT "${HEXAGON_TMP2}" CACHE PATH
"Root directory of Hexagon SDK")
else(HEXAGON_AEESTDDEF)
message(SEND_ERROR "Cannot validate Hexagon SDK in ${USE_HEXAGON_SDK}")
endif()
endfunction()
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()
# If USE_HEXAGON_DEVICE is set to a valid value, make sure that USE_HEXAGON_SDK
# is defined.
if (NOT USE_HEXAGON_SDK)
message(SEND_ERROR "Please set USE_HEXAGON_SDK to the Hexagon SDK root")
return()
endif()
if(USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}")
find_hexagon_toolchain()
message(STATUS "Hexagon toolchain: ${HEXAGON_TOOLCHAIN}")
file(GLOB RUNTIME_HEXAGON_SIM_SRCS src/runtime/hexagon/sim/*.cc)
include_directories("${HEXAGON_TOOLCHAIN}/include/iss")
link_directories("${HEXAGON_TOOLCHAIN}/lib/iss")
list(APPEND TVM_RUNTIME_LINKER_LIBS "-lwrapper")
elseif(USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}")
find_hexagon_sdk_root()
find_hexagon_toolchain()
message(STATUS "Hexagon SDK: ${HEXAGON_SDK_ROOT}")
file(GLOB RUNTIME_HEXAGON_DEVICE_SRCS src/runtime/hexagon/target/*.cc)
include_directories("${HEXAGON_SDK_ROOT}/incs/stddef")
include_directories("${HEXAGON_SDK_ROOT}/libs/common/rpcmem/inc")
include_directories(
"${HEXAGON_SDK_ROOT}/libs/common/remote/ship/android_Release_aarch64")
include_directories("${HEXAGON_TOOLCHAIN}/include/iss")
list(APPEND TVM_RUNTIME_LINKER_LIBS "-ldl")
endif()
file(GLOB RUNTIME_HEXAGON_SRCS src/runtime/hexagon/*.cc)
list(APPEND RUNTIME_SRCS ${RUNTIME_HEXAGON_SRCS} ${RUNTIME_HEXAGON_SIM_SRCS}
${RUNTIME_HEXAGON_DEVICE_SRCS})
......@@ -82,6 +82,7 @@ typedef enum {
kDLSDAccel = 6,
kOpenGL = 11,
kDLMicroDev = 13,
kDLHexagon = 14,
// AddExtraTVMType which is not in DLPack here
} TVMDeviceExtType;
......
......@@ -47,10 +47,10 @@ enum DeviceAttrKind : int {
};
/*! \brief Number of bytes each allocation must align to */
constexpr int kAllocAlignment = 64;
constexpr int kAllocAlignment = 128;
/*! \brief Number of bytes each allocation must align to in temporary allocation */
constexpr int kTempAllocaAlignment = 64;
constexpr int kTempAllocaAlignment = 128;
/*! \brief Maximum size that can be allocated on stack */
constexpr int kMaxStackAlloca = 1024;
......@@ -218,6 +218,7 @@ inline const char* DeviceName(int type) {
case kOpenGL: return "opengl";
case kDLExtDev: return "ext_dev";
case kDLMicroDev: return "micro_dev";
case kDLHexagon: return "hexagon";
default: LOG(FATAL) << "unknown type =" << type; return "Unknown";
}
}
......
......@@ -177,6 +177,10 @@ TVM_DLL Target stackvm(const std::vector<std::string>& options =
/*! \return A target for external device */
TVM_DLL Target ext_dev(const std::vector<std::string>& options =
std::vector<std::string>());
/*! \return A target for hexagon */
TVM_DLL Target hexagon(const std::vector<std::string>& options =
std::vector<std::string>());
} // namespace target
/*!
......
......@@ -33,6 +33,7 @@ public class TVMContext {
MASK2STR.put(7, "vulkan");
MASK2STR.put(8, "metal");
MASK2STR.put(9, "vpi");
MASK2STR.put(14, "hexagon");
STR2MASK.put("cpu", 1);
STR2MASK.put("gpu", 2);
......@@ -42,6 +43,7 @@ public class TVMContext {
STR2MASK.put("vulkan", 7);
STR2MASK.put("metal", 8);
STR2MASK.put("vpi", 9);
STR2MASK.put("hexagon", 14);
}
/**
......@@ -122,6 +124,19 @@ public class TVMContext {
return vpi(0);
}
/**
* Construct a Hexagon device.
* @param devId The device id
* @return The created context
*/
public static TVMContext hexagon(int devId) {
return new TVMContext(14, devId);
}
public static TVMContext hexagon() {
return hexagon(0);
}
public final int deviceType;
public final int deviceId;
......
......@@ -30,7 +30,7 @@ from ._ffi import register_object, register_func, register_extension, get_global
# tvm.runtime
from .runtime.object import Object
from .runtime.ndarray import context, cpu, gpu, opencl, cl, vulkan, metal, mtl
from .runtime.ndarray import vpi, rocm, opengl, ext_dev, micro_dev
from .runtime.ndarray import vpi, rocm, opengl, ext_dev, micro_dev, hexagon
from .runtime import ndarray as nd
# tvm.error
......
......@@ -145,6 +145,7 @@ class TVMContext(ctypes.Structure):
11: 'opengl',
12: 'ext_dev',
13: 'micro_dev',
14: 'hexagon',
}
STR2MASK = {
'llvm': 1,
......@@ -166,6 +167,7 @@ class TVMContext(ctypes.Structure):
'opengl': 11,
'ext_dev': 12,
'micro_dev': 13,
'hexagon': 14,
}
def __init__(self, device_type, device_id):
super(TVMContext, self).__init__()
......
......@@ -462,6 +462,22 @@ def micro_dev(dev_id=0):
return TVMContext(13, dev_id)
def hexagon(dev_id=0):
"""Construct a Hexagon device
Parameters
----------
dev_id : int, optional
The integer device id
Returns
-------
ctx : TVMContext
The created context
"""
return TVMContext(14, dev_id)
cl = opencl
mtl = metal
......
......@@ -55,7 +55,7 @@ We can use :py:func:`tvm.target.create` to create a tvm.target.Target from the t
We can also use other specific function in this module to create specific targets.
"""
from .target import Target, create
from .target import cuda, rocm, mali, intel_graphics, opengl, arm_cpu, rasp, vta, bifrost
from .target import cuda, rocm, mali, intel_graphics, opengl, arm_cpu, rasp, vta, bifrost, hexagon
from .generic_func import GenericFunc
from .generic_func import generic_func, get_native_generic_func, override_native_generic_func
from . import datatype
......
......@@ -247,6 +247,103 @@ def bifrost(model='unknown', options=None):
return _ffi_api.TargetCreate("opencl", *opts)
def hexagon(cpu_ver='v66', sim_args=None, hvx=128):
"""Returns a Hexagon target.
Parameters
----------
cpu_ver : str
CPU version used for code generation. Not all allowed cpu str
will be valid, LLVM will throw an error.
sim_args : str or list of str
User defined sim arguments. CPU version defaults to cpu_ver.
Otherwise, separate versions are used for codegen and sim. Not
all allowed cpu strings will be valid, simulator will throw an
error if invalid. Does not affect codegen.
hvx : int
Size of hvx register. Value of 0 indicates disabled hvx.
"""
# Example compiler arguments
# llvm -target=hexagon -mcpu=hexagonv66 -mattr=+hvxv66,+hvx-length128b
# Check for valid codegen cpu
valid_hex = ['v60', 'v62', 'v65', 'v66', 'v67', 'v67t']
try:
cpu_ver = cpu_ver[cpu_ver.index('v'):].lower()
assert 3 <= len(cpu_ver) <= 4
except:
msg = '{} is not a valid Hexagon version\nvalid versions include {}'
raise ValueError(msg.format(cpu_ver, valid_hex)) from None
assert hvx in [0, 64, 128]
# Target string
def create_target(cpu_ver):
target = ' -target=hexagon'
mcpu = ' -mcpu=hexagon' + cpu_ver
mattr = ''
# HVX enable
if hvx:
mattr = ' -mattr=+hvx' + cpu_ver + ',+hvx-length' + str(hvx) + 'b'
return 'llvm' + target + mcpu + mattr
# Simulator string
def create_sim(cpu_ver, sim_args):
def validate_hvx_length(codegen_hvx, sim_args):
if sim_args and '--hvx_length' in sim_args:
# If --hvx_length was specified, check HVX length of sim
# vs codegen
i = sim_args.index('hvx_length') + len('hvx_length') + 1
sim_hvx = sim_args[i:i+3]
if sim_hvx != str(codegen_hvx):
print('WARNING: sim hvx {} and codegen hvx {} mismatch!' \
.format(sim_hvx, codegen_hvx))
elif codegen_hvx != 0:
# If --hvx_length was not given, add it if HVX is enabled
sim_args = sim_args + ' ' if isinstance(sim_args, str) else ''
sim_args += '--hvx_length ' + str(codegen_hvx)
return sim_args or ''
if not sim_args:
return cpu_ver + ' ' + validate_hvx_length(hvx, sim_args)
sim_cpu = cpu_ver + ' '
# Add user defined args
if isinstance(sim_args, list):
sim_args = ' '.join(sim_args)
# Check for supplied sim cpu version
if 'v6' in sim_args:
sim_cpu = ''
# Regex match for allowed cpus
valid_cpu_str_regex = r'(?P<pre>--.*\s)?(--m)?' + \
r'(?P<base_version>v6[25678])(?P<sub_version>[a-z])?' + \
r'(?P<l2_size>_[0-9]+)?(?P<rev>_rev[0-9])?\s?(?P<post>--.*)?'
m = re.match(valid_cpu_str_regex, sim_args.lower())
if not m:
raise ValueError(
'Invalid simulator argument string "{}"'.format(sim_args))
# Parse options into correct order
cpu_attr = {x: str(m.groupdict()[x] or '') for x in m.groupdict()}
sim_args = cpu_attr['base_version'] + \
cpu_attr['sub_version'] + \
cpu_attr['l2_size'] + \
cpu_attr['rev'] + ' ' + \
cpu_attr['pre'] + cpu_attr['post']
return sim_cpu + ' ' + validate_hvx_length(hvx, sim_args)
# Sim args
os.environ['HEXAGON_SIM_ARGS'] = create_sim(cpu_ver, sim_args)
target_str = create_target(cpu_ver)
args_list = target_str.split()
return _ffi_api.TargetCreate("hexagon", *args_list)
def create(target_str):
"""Get a target given target string.
......
<!--- 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. -->
# Hexagon backend runtime
The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
- X86/Linux host running Hexagon simulator,
- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0 or later. The Hexagon SDK can be downloaded from https://developer.qualcomm.com/software/hexagon-dsp-sdk.
It is also recommended to use as recent version of LLVM as possible, version 7.0.0 being the minimum (based on community feedback).
### Compiling TVM runtime for x86
This will use Hexagon simulator, which is provided in the Hexagon SDK.
When configuring TVM (cmake), set the following variables:
```
USE_LLVM=llvm-config
USE_HEXAGON_DEVICE=sim
USE_HEXAGON_SDK=/path/to/sdk
```
You can then build the entire TVM with the usual command (e.g. `make`).
### Compiling TVM runtime for Android
This will use FastRPC mechanism to communicate between the AArch64 host and Hexagon.
When configuring TVM (cmake), set the following variables:
```
USE_LLVM=llvm-config
USE_HEXAGON_DEVICE=device
USE_HEXAGON_SDK=/path/to/sdk
```
You will need Android clang toolchain to compile the runtime. It is provided in Android NDK r19 or newer.
Set the C/C++ compiler to the Android clang for aarch64, and pass `-DCMAKE_CXX_FLAGS='-stdlib=libc++'` to the cmake command.
Only build the `runtime` component of TVM (e.g. `make runtime`), building the entire TVM will not work.
### Compiling TVM runtime for Hexagon
The TVM runtime executing on Hexagon does not need to have support for Hexagon device in it (as it is only for communication between host and Hexagon device). In fact, it's only needed for basic services (like thread control), and so it should not contain support for any devices.
When configuring TVM (cmake), set the following variables:
```
USE_RPC=OFF
USE_LLVM=OFF
USE_HEXAGON_DEVICE=OFF
USE_HEXAGON_SDK=/path/to/sdk
```
Please note that while suport for a Hexagon device is disabled, the Hexagon SDK is still needed and the path to it needs to be passed to cmake.
Set the C/C++ compiler to `hexagon-clang` (included in the Hexagon SDK), and set `CMAKE_CXX_FLAGS='-stdlib=libc++'`.
As in the case of Android, only build the `runtime` component (e.g. `make runtime`).
/*
* 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 <dmlc/logging.h>
#include <tvm/runtime/device_api.h>
#include <tvm/runtime/registry.h>
#include <algorithm>
#include <cstring>
#include "hexagon_module.h"
namespace tvm {
namespace runtime {
class HexagonDeviceAPI : public DeviceAPI {
public:
void SetDevice(TVMContext ctx) final;
void GetAttr(TVMContext ctx, DeviceAttrKind kind, TVMRetValue* rv) final;
void* AllocDataSpace(TVMContext ctx, size_t nbytes, size_t alignment,
DLDataType type_hint) final;
void FreeDataSpace(TVMContext ctx, void* ptr) final;
void CopyDataFromTo(const void* from, size_t from_offset, void* to,
size_t to_offset, size_t num_bytes, TVMContext ctx_from,
TVMContext ctx_to, DLDataType type_hint,
TVMStreamHandle stream) final;
void StreamSync(TVMContext ctx, TVMStreamHandle stream) final;
void* AllocWorkspace(TVMContext ctx, size_t nbytes,
DLDataType type_hint = {}) final;
void FreeWorkspace(TVMContext ctx, void* ptr) final;
static const std::shared_ptr<HexagonDeviceAPI>& Global() {
static std::shared_ptr<HexagonDeviceAPI> inst =
std::make_shared<HexagonDeviceAPI>();
return inst;
}
};
// HexagonDeviceAPI.
inline void HexagonDeviceAPI::SetDevice(TVMContext ctx) {}
inline void HexagonDeviceAPI::GetAttr(TVMContext ctx, DeviceAttrKind kind,
TVMRetValue* rv) {
if (kind == kExist) *rv = 1;
}
inline void* HexagonDeviceAPI::AllocDataSpace(TVMContext ctx, size_t nbytes,
size_t alignment,
DLDataType type_hint) {
CHECK(hexagon::Device::ValidateDeviceId(ctx.device_id));
return hexagon::Device::Global()->Alloc(nbytes, alignment);
}
inline void HexagonDeviceAPI::FreeDataSpace(TVMContext ctx, void* ptr) {
CHECK(hexagon::Device::ValidateDeviceId(ctx.device_id));
hexagon::Device::Global()->Free(ptr);
}
inline void HexagonDeviceAPI::CopyDataFromTo(
const void* from, size_t from_offset, void* to, size_t to_offset,
size_t num_bytes, TVMContext ctx_from, TVMContext ctx_to,
DLDataType type_hint, TVMStreamHandle stream) {
const char* src = static_cast<const char*>(from) + from_offset;
char* dst = static_cast<char*>(to) + to_offset;
auto Is32bit = [](const void* p) {
return p == reinterpret_cast<const void*>(uint32_t(uintptr_t(p)));
};
(void)Is32bit;
if (ctx_from.device_type == ctx_to.device_type) {
if (ctx_from.device_type == kDLCPU) {
memmove(dst, src, num_bytes);
} else if (static_cast<int>(ctx_from.device_type) == kDLHexagon) {
CHECK(hexagon::Device::ValidateDeviceId(ctx_from.device_id));
CHECK_EQ(ctx_from.device_id, ctx_to.device_id);
CHECK(Is32bit(dst) && Is32bit(src));
hexagon::Device::Global()->CopyDeviceToDevice(dst, src, num_bytes);
}
} else {
if (ctx_from.device_type == kDLCPU) {
CHECK_EQ(static_cast<int>(ctx_to.device_type), kDLHexagon);
CHECK(Is32bit(dst));
CHECK(hexagon::Device::ValidateDeviceId(ctx_to.device_id));
hexagon::Device::Global()->CopyHostToDevice(dst, src, num_bytes);
} else {
CHECK_EQ(static_cast<int>(ctx_from.device_type), kDLHexagon);
CHECK_EQ(ctx_to.device_type, kDLCPU);
CHECK(Is32bit(src));
CHECK(hexagon::Device::ValidateDeviceId(ctx_from.device_id));
hexagon::Device::Global()->CopyDeviceToHost(dst, src, num_bytes);
}
}
}
inline void HexagonDeviceAPI::StreamSync(TVMContext ctx,
TVMStreamHandle stream) {}
inline void* HexagonDeviceAPI::AllocWorkspace(TVMContext ctx, size_t nbytes,
DLDataType type_hint) {
CHECK(hexagon::Device::ValidateDeviceId(ctx.device_id));
if (type_hint.code == 100) {
size_t align = std::min(nbytes, 2048lu);
return hexagon::Device::Global()->AllocVtcm(nbytes, align);
}
return DeviceAPI::AllocWorkspace(ctx, nbytes, type_hint);
}
inline void HexagonDeviceAPI::FreeWorkspace(TVMContext ctx, void* ptr) {
CHECK(hexagon::Device::ValidateDeviceId(ctx.device_id));
DeviceAPI::FreeWorkspace(ctx, ptr);
}
TVM_REGISTER_GLOBAL("device_api.hexagon")
.set_body([](TVMArgs args, TVMRetValue* rv) {
DeviceAPI* ptr = HexagonDeviceAPI::Global().get();
*rv = ptr;
});
} // namespace runtime
} // namespace tvm
// Hexagon-specific runtime functions to allocate/deallocate workspaces
// in VTCM.
extern "C" {
void* HexagonBackendAllocateVTCM(uint32_t nbytes, uint32_t align) {
align = std::max(align, 2048u);
return tvm::runtime::hexagon::Device::Global()->AllocVtcm(nbytes, align);
}
void HexagonBackendFreeVTCM(void* ptr) {
return tvm::runtime::hexagon::Device::Global()->FreeVtcm(ptr);
}
}
/*
* 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_MODULE_H_
#define TVM_RUNTIME_HEXAGON_HEXAGON_MODULE_H_
#include <dmlc/logging.h>
#include <tvm/runtime/module.h>
#include <array>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include "../meta_data.h"
namespace tvm {
namespace runtime {
/*!
* \brief Create a Hexagon module from data.
* \param data The module data.
* \param fmt The format of the data, can be "obj".
* \param fmap The function information map of each function.
* \param asm_str String with the generated assembly source.
* \param obj_str String with the object file data.
* \param ir_str String with the disassembled LLVM IR source.
* \param bc_str String with the bitcode LLVM IR.
* \param packed_c_abi Set of names of functions using PackedC calling
* convention.
*/
Module HexagonModuleCreate(std::string data, std::string fmt,
std::unordered_map<std::string, FunctionInfo> fmap,
std::string asm_str, std::string obj_str,
std::string ir_str, std::string bc_str,
const std::set<std::string>& packed_c_abi);
namespace hexagon {
/*!
* \brief Low-level interface for communicating with Hexagon devices.
*/
class Device {
public:
/*!
* \brief Allocate memory on device.
* \param size Requested size.
* \param align Requested alignment.
* \return Pointer (local to the device) of the allocated memory,
* or nullptr if allocation failed.
*/
virtual void* Alloc(unsigned size, unsigned align) = 0;
/*!
* \brief Release allocated memory on device.
* \param ptr Pointer to memory previously allocated by \ref Alloc.
*/
virtual void Free(void* ptr) = 0;
/*!
* \brief Allocate VTCM memory on device.
* \param size Requested size.
* \param align Requested alignment.
* \return Pointer (local to the device) of the allocated memory,
* or nullptr if allocation failed.
*/
virtual void* AllocVtcm(unsigned size, unsigned align) = 0;
/*!
* \brief Release allocated VTCM memory on device.
* \param ptr Pointer to memory previously allocated by \ref AllocVtcm.
*/
virtual void FreeVtcm(void* ptr) = 0;
/*!
* \brief Copy a block of data on device to another location on the device.
* \param dst Pointer (local to device) to the destination buffer.
* \param src Pointer (local to device) of the source buffer.
* \param len Number of bytes to copy.
*/
virtual void CopyDeviceToDevice(void* dst, const void* src,
unsigned len) = 0;
/*!
* \brief Copy a block of data from device to host.
* \param host_dst Pointer (local to host) to the destination buffer.
* \param src Pointer (local to device) to the source buffer.
* \param len Number of bytes to copy.
*/
virtual void CopyDeviceToHost(void* host_dst, const void* src,
unsigned len) = 0;
/*!
* \brief Copy a block of data from host to device.
* \param dst Pointer (local to device) to the destination buffer.
* \param host_src Pointer (local to host) to the source buffer.
* \param len Number of bytes to copy.
*/
virtual void CopyHostToDevice(void* dst, const void* host_src,
unsigned len) = 0;
/*!
* \brief Load a module (typically a shared library) into device.
* \param data Name of the shared library.
* \param fmt Format of the library (currently ignored).
* \return Pointer to the loaded module.
* \note Currently only one module can be loaded at any given time.
*/
virtual void* Load(const std::string& data, const std::string& fmt) = 0;
/*!
* \brief Unload a module from device.
* \param mod Pointer to a loaded module returned by \ref Load.
*/
virtual void Unload(void* mod) = 0;
/*!
* \brief Find the address of an object in the currently loaded module.
* \param sym Name of the object.
* \return Address of the located object, or nullptr if object was
* not found.
*/
virtual void* Resolve(const std::string& sym) = 0;
/*!
* \brief Invoke a function on device with given arguments.
* \param func Address (local to device) of the function to call.
* \param scalar Pointer to an array of 32-bit values that will be
* passed via consecutive registers: r0..r5. This array
* includes dummy values for skipped registers.
* \param sc_num Number of values in the "scalar" array.
* \param stack Pointer to an array of 32-bit values that will be
* passed on the stack. This array includes dummy values
* for padding.
* \param st_num Number of values in the "stack" array.
*/
virtual void Call(void* func, uint32_t* scalar, unsigned sc_num,
uint32_t* stack, unsigned st_num) = 0;
virtual ~Device() = 0;
static std::shared_ptr<Device> Global();
static bool ValidateDeviceId(decltype(DLContext::device_id) device_id) {
// Only supporting a single device for now.
return device_id == 0;
}
};
} // namespace hexagon
} // namespace runtime
} // namespace tvm
#endif // TVM_RUNTIME_HEXAGON_HEXAGON_MODULE_H_
/*
* 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.
*/
#if defined(__hexagon__)
#include <errno.h>
#include <stdlib.h>
extern "C" {
int posix_memalign(void** memptr, size_t alignment, size_t size)
__attribute__((nothrow));
}
__attribute__((nothrow)) int posix_memalign(void** memptr, size_t alignment,
size_t size) {
if (void* p = memalign(alignment, size)) {
*memptr = p;
return 0;
}
return ENOMEM;
}
#endif
/*
* 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_SIM_HEXAGON_SIM_PROTO_H_
#define TVM_RUNTIME_HEXAGON_SIM_HEXAGON_SIM_PROTO_H_
// Protocol:
// Host >-- [ code:MsgReq, len:amount requested, va:_ ] --> Remote
// Host <-- [ code:MsqAck, len:amount provided, va:address ] --< Remote
// Host >-- [ code:message, len:payload length, va:address ] --> Remote
// Host <-- [ code:None, len:response length, va:address ] --< Remote
enum : uint32_t {
kNone,
kMsgReq,
kMsgAck,
kAlloc,
kFree,
kCopy,
kLoad,
kUnload,
kResolve,
kCall,
kFlush,
kAllocVtcm
};
struct Message {
uint32_t code;
uint32_t len;
uint32_t va;
} __attribute__((packed));
struct MsgAlloc {
uint32_t size;
uint32_t align;
} __attribute__((packed));
struct MsgPointer {
uint32_t va;
} __attribute__((packed));
struct MsgCopy {
uint32_t dst;
uint32_t src;
uint32_t len;
} __attribute__((packed));
struct MsgCall {
uint32_t func_va; // offset: 0
uint32_t scalar_num; // 4
uint32_t stack_num; // 8
uint32_t data[]; // 12
} __attribute__((packed));
#endif // TVM_RUNTIME_HEXAGON_SIM_HEXAGON_SIM_PROTO_H_
/*
* 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_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_H_
#define TVM_RUNTIME_HEXAGON_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_H_
/// @file tvm_hexagon_remote.idl
/// IDL to offload TVM kernels to Hexagon from APPS for multi-domains
#include "AEEStdDef.h"
#include "remote.h"
#ifndef __QAIC_HEADER
#define __QAIC_HEADER(ff) ff
#endif // __QAIC_HEADER
#ifndef __QAIC_HEADER_EXPORT
#define __QAIC_HEADER_EXPORT
#endif // __QAIC_HEADER_EXPORT
#ifndef __QAIC_HEADER_ATTRIBUTE
#define __QAIC_HEADER_ATTRIBUTE
#endif // __QAIC_HEADER_ATTRIBUTE
#ifndef __QAIC_IMPL
#define __QAIC_IMPL(ff) ff
#endif // __QAIC_IMPL
#ifndef __QAIC_IMPL_EXPORT
#define __QAIC_IMPL_EXPORT
#endif // __QAIC_IMPL_EXPORT
#ifndef __QAIC_IMPL_ATTRIBUTE
#define __QAIC_IMPL_ATTRIBUTE
#endif // __QAIC_IMPL_ATTRIBUTE
#ifdef __cplusplus
extern "C" {
#endif
/**
* Opens the handle in the specified domain. If this is the first
* handle, this creates the session. Typically this means opening
* the device, aka open("/dev/adsprpc-smd"), then calling ioctl
* device APIs to create a PD on the DSP to execute our code in,
* then asking that PD to dlopen the .so and dlsym the skel function.
*
* @param uri, <interface>_URI"&_dom=aDSP"
* <interface>_URI is a QAIC generated uri, or
* "file:///<sofilename>?<interface>_skel_handle_invoke&_modver=1.0"
* If the _dom parameter is not present, _dom=DEFAULT is assumed
* but not forwarded.
* Reserved uri keys:
* [0]: first unamed argument is the skel invoke function
* _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT
* _modver: module version, _modver=1.0
* _*: any other key name starting with an _ is reserved
* Unknown uri keys/values are forwarded as is.
* @param h, resulting handle
* @retval, 0 on success
*/
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_open)(
const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE;
/**
* Closes a handle. If this is the last handle to close, the session
* is closed as well, releasing all the allocated resources.
* @param h, the handle to close
* @retval, 0 on success, should always succeed
*/
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_close)(
remote_handle64 h) __QAIC_HEADER_ATTRIBUTE;
typedef struct _tvm_hexagon_remote_buffer__seq_octet
_tvm_hexagon_remote_buffer__seq_octet;
typedef _tvm_hexagon_remote_buffer__seq_octet tvm_hexagon_remote_buffer;
struct _tvm_hexagon_remote_buffer__seq_octet {
unsigned char* data;
int dataLen;
};
typedef unsigned int tvm_hexagon_remote_handle_t;
typedef uint64 tvm_hexagon_remote_scalar_t;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_load_library)(
remote_handle64 _h, const char* soname, int sonameLen, const char* code,
int codeLen,
tvm_hexagon_remote_handle_t* module_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_get_symbol)(
remote_handle64 _h, tvm_hexagon_remote_handle_t module_ptr,
const char* name, int nameLen,
tvm_hexagon_remote_handle_t* sym_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_kernel)(
remote_handle64 _h, tvm_hexagon_remote_handle_t module_ptr,
tvm_hexagon_remote_handle_t symbol, int* scalar, int scalarLen, int* stack,
int stackLen, const tvm_hexagon_remote_buffer* scalar_in_octet,
int scalar_in_octetLen, tvm_hexagon_remote_buffer* scalar_out_octet,
int scalar_out_octetLen, const tvm_hexagon_remote_buffer* stack_in_octet,
int stack_in_octetLen, tvm_hexagon_remote_buffer* stack_out_octet,
int stack_out_octetLen, uint64* pcycles,
uint64* time_usec) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_release_library)(
remote_handle64 _h,
tvm_hexagon_remote_handle_t module_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_alloc_vtcm)(
remote_handle64 _h, unsigned int size, unsigned int align,
unsigned int* dsp_va) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_free_vtcm)(
remote_handle64 _h, unsigned int dsp_va) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_call_mmap64)(
remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE;
#ifndef tvm_hexagon_remote_URI
#define tvm_hexagon_remote_URI \
"file:///" \
"libtvm_hexagon_remote_skel.so?tvm_hexagon_remote_skel_handle_invoke&_" \
"modver=1.0"
#endif /*tvm_hexagon_remote_URI*/
#ifdef __cplusplus
}
#endif
#endif // TVM_RUNTIME_HEXAGON_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_H_
/*
* 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_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_ND_H_
#define TVM_RUNTIME_HEXAGON_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_ND_H_
/// @file tvm_hexagon_remote_nd.idl
/// IDL to offload TVM kernels to Hexagon from APPS for non-domains
#include "AEEStdDef.h"
#include "remote.h"
#ifndef __QAIC_HEADER
#define __QAIC_HEADER(ff) ff
#endif // __QAIC_HEADER
#ifndef __QAIC_HEADER_EXPORT
#define __QAIC_HEADER_EXPORT
#endif // __QAIC_HEADER_EXPORT
#ifndef __QAIC_HEADER_ATTRIBUTE
#define __QAIC_HEADER_ATTRIBUTE
#endif // __QAIC_HEADER_ATTRIBUTE
#ifndef __QAIC_IMPL
#define __QAIC_IMPL(ff) ff
#endif // __QAIC_IMPL
#ifndef __QAIC_IMPL_EXPORT
#define __QAIC_IMPL_EXPORT
#endif // __QAIC_IMPL_EXPORT
#ifndef __QAIC_IMPL_ATTRIBUTE
#define __QAIC_IMPL_ATTRIBUTE
#endif // __QAIC_IMPL_ATTRIBUTE
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _tvm_hexagon_remote_nd_buffer__seq_octet
_tvm_hexagon_remote_nd_buffer__seq_octet;
typedef _tvm_hexagon_remote_nd_buffer__seq_octet tvm_hexagon_remote_nd_buffer;
struct _tvm_hexagon_remote_nd_buffer__seq_octet {
unsigned char* data;
int dataLen;
};
typedef unsigned int tvm_hexagon_remote_nd_handle_t;
typedef uint64 tvm_hexagon_remote_nd_scalar_t;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_open)(void)
__QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_close)(void)
__QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_load_library)(
const char* soname, int sonameLen, const char* code, int codeLen,
tvm_hexagon_remote_nd_handle_t* module_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_get_symbol)(
tvm_hexagon_remote_nd_handle_t module_ptr, const char* name, int nameLen,
tvm_hexagon_remote_nd_handle_t* sym_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_kernel)(
tvm_hexagon_remote_nd_handle_t module_ptr,
tvm_hexagon_remote_nd_handle_t symbol, int* scalar, int scalarLen,
int* stack, int stackLen,
const tvm_hexagon_remote_nd_buffer* scalar_in_octet,
int scalar_in_octetLen, tvm_hexagon_remote_nd_buffer* scalar_out_octet,
int scalar_out_octetLen,
const tvm_hexagon_remote_nd_buffer* stack_in_octet, int stack_in_octetLen,
tvm_hexagon_remote_nd_buffer* stack_out_octet, int stack_out_octetLen,
uint64* pcycles, uint64* time_usec) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_release_library)(
tvm_hexagon_remote_nd_handle_t module_ptr) __QAIC_HEADER_ATTRIBUTE;
__QAIC_HEADER_EXPORT int __QAIC_HEADER(tvm_hexagon_remote_nd_call_mmap64)(void)
__QAIC_HEADER_ATTRIBUTE;
#ifdef __cplusplus
}
#endif
#endif // TVM_RUNTIME_HEXAGON_TARGET_FASTRPC_TVM_HEXAGON_REMOTE_ND_H_
/*
* 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.
*/
#ifdef __ANDROID__
#include "hexagon_dsprpcapi.h"
#include <dlfcn.h>
#include <dmlc/logging.h>
#include <stdint.h>
#include "hexagon_target_log.h"
namespace tvm {
namespace runtime {
namespace hexagon {
DspRpcAPI::DspRpcAPI() {
CHECK(lib_handle_ = dlopen(rpc_lib_name_, RTLD_LAZY | RTLD_LOCAL));
#define RESOLVE(n) n##_ = GetSymbol<n##_t*>(#n)
RESOLVE(remote_handle_close);
RESOLVE(remote_handle_control);
RESOLVE(remote_handle_invoke);
RESOLVE(remote_handle_open);
RESOLVE(remote_mmap);
RESOLVE(remote_munmap);
RESOLVE(remote_handle64_close);
RESOLVE(remote_handle64_control);
RESOLVE(remote_handle64_invoke);
RESOLVE(remote_handle64_open);
RESOLVE(remote_mmap64);
RESOLVE(remote_munmap64);
RESOLVE(remote_register_buf);
RESOLVE(remote_register_buf_attr);
RESOLVE(remote_register_dma_handle);
RESOLVE(remote_register_dma_handle_attr);
RESOLVE(remote_register_fd);
RESOLVE(remote_session_control);
RESOLVE(remote_set_mode);
RESOLVE(rpcmem_init);
RESOLVE(rpcmem_deinit);
RESOLVE(rpcmem_alloc);
RESOLVE(rpcmem_free);
RESOLVE(rpcmem_to_fd);
#undef RESOLVE
}
DspRpcAPI::~DspRpcAPI() {
if (lib_handle_) dlclose(lib_handle_);
}
template <typename T>
T DspRpcAPI::GetSymbol(const char* sym) {
if (!lib_handle_) {
TVM_LOGE("error looking up symbol \"%s\": library not loaded", sym);
return nullptr;
}
dlerror(); // Clear any previous errror conditions.
if (T ret = reinterpret_cast<T>(dlsym(lib_handle_, sym))) {
return ret;
}
const char* err = dlerror();
const char* err_txt = err ? err : "symbol not found";
TVM_LOGD("error looking up symbol \"%s\": %s", sym, err_txt);
return nullptr;
}
const DspRpcAPI* DspRpcAPI::Global() {
static const DspRpcAPI dsp_api;
return &dsp_api;
}
} // namespace hexagon
} // namespace runtime
} // namespace tvm
#endif // __ANDROID__
/*
* 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_TARGET_HEXAGON_DSPRPCAPI_H_
#define TVM_RUNTIME_HEXAGON_TARGET_HEXAGON_DSPRPCAPI_H_
#ifdef __ANDROID__
#include <dmlc/logging.h>
#include <stdint.h>
#include "remote.h"
#include "remote64.h"
#include "rpcmem.h"
namespace tvm {
namespace runtime {
namespace hexagon {
/*!
* Encapsulation of the API of lib(a|c)dsprpc.so (loaded via dlopen), allowing
* for having versions of the library that do not implement all of the
* functions.
*
* Functions defined in the DSP RPC library:
* remote_handle_close
* remote_handle_control
* remote_handle_invoke
* remote_handle_open
* remote_mmap
* remote_munmap
*
* remote_handle64_close
* remote_handle64_control
* remote_handle64_invoke
* remote_handle64_open
* remote_mmap64
* remote_munmap64
*
* remote_register_buf
* remote_register_buf_attr
* remote_register_dma_handle
* remote_register_dma_handle_attr
* remote_register_fd
*
* remote_session_control
* remote_set_mode
*
* rpcmem_init
* rpcmem_deinit
* rpcmem_alloc
* rpcmem_free
* rpcmem_to_fd
*/
class DspRpcAPI {
public:
DspRpcAPI();
~DspRpcAPI();
using remote_handle = ::remote_handle;
using remote_handle64 = ::remote_handle64;
#define DECLTYPE(ty) using ty##_t = decltype(::ty);
DECLTYPE(remote_handle_close)
DECLTYPE(remote_handle_control)
DECLTYPE(remote_handle_invoke)
DECLTYPE(remote_handle_open)
DECLTYPE(remote_mmap)
DECLTYPE(remote_munmap)
DECLTYPE(remote_handle64_close)
DECLTYPE(remote_handle64_control)
DECLTYPE(remote_handle64_invoke)
DECLTYPE(remote_handle64_open)
DECLTYPE(remote_mmap64)
DECLTYPE(remote_munmap64)
DECLTYPE(remote_register_buf)
DECLTYPE(remote_register_buf_attr)
DECLTYPE(remote_register_dma_handle)
DECLTYPE(remote_register_dma_handle_attr)
DECLTYPE(remote_register_fd)
DECLTYPE(remote_session_control)
DECLTYPE(remote_set_mode)
DECLTYPE(rpcmem_init)
DECLTYPE(rpcmem_deinit)
DECLTYPE(rpcmem_alloc)
DECLTYPE(rpcmem_free)
DECLTYPE(rpcmem_to_fd)
#undef DECLTYPE
#define DECLFUNC(fn) \
fn##_t* fn##_ptr(bool allow_nullptr = false) const { \
if (!allow_nullptr) CHECK(fn##_ != nullptr); \
return fn##_; \
}
DECLFUNC(remote_handle_close)
DECLFUNC(remote_handle_control)
DECLFUNC(remote_handle_invoke)
DECLFUNC(remote_handle_open)
DECLFUNC(remote_mmap)
DECLFUNC(remote_munmap)
DECLFUNC(remote_handle64_close)
DECLFUNC(remote_handle64_control)
DECLFUNC(remote_handle64_invoke)
DECLFUNC(remote_handle64_open)
DECLFUNC(remote_mmap64)
DECLFUNC(remote_munmap64)
DECLFUNC(remote_register_buf)
DECLFUNC(remote_register_buf_attr)
DECLFUNC(remote_register_dma_handle)
DECLFUNC(remote_register_dma_handle_attr)
DECLFUNC(remote_register_fd)
DECLFUNC(remote_session_control)
DECLFUNC(remote_set_mode)
DECLFUNC(rpcmem_init)
DECLFUNC(rpcmem_deinit)
DECLFUNC(rpcmem_alloc)
DECLFUNC(rpcmem_free)
DECLFUNC(rpcmem_to_fd)
#undef DECLFUNC
static const DspRpcAPI* Global();
private:
static constexpr const char* rpc_lib_name_ = "libadsprpc.so";
void* lib_handle_ = nullptr;
#define DECLPTR(p) p##_t* p##_ = nullptr;
DECLPTR(remote_handle_close)
DECLPTR(remote_handle_control)
DECLPTR(remote_handle_invoke)
DECLPTR(remote_handle_open)
DECLPTR(remote_mmap)
DECLPTR(remote_munmap)
DECLPTR(remote_handle64_close)
DECLPTR(remote_handle64_control)
DECLPTR(remote_handle64_invoke)
DECLPTR(remote_handle64_open)
DECLPTR(remote_mmap64)
DECLPTR(remote_munmap64)
DECLPTR(remote_register_buf)
DECLPTR(remote_register_buf_attr)
DECLPTR(remote_register_dma_handle)
DECLPTR(remote_register_dma_handle_attr)
DECLPTR(remote_register_fd)
DECLPTR(remote_session_control)
DECLPTR(remote_set_mode)
DECLPTR(rpcmem_init)
DECLPTR(rpcmem_deinit)
DECLPTR(rpcmem_alloc)
DECLPTR(rpcmem_free)
DECLPTR(rpcmem_to_fd)
#undef DECLPTR
template <typename T>
T GetSymbol(const char* sym);
};
} // namespace hexagon
} // namespace runtime
} // namespace tvm
#endif // __ANDROID__
#endif // TVM_RUNTIME_HEXAGON_TARGET_HEXAGON_DSPRPCAPI_H_
/*
* 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.
*/
#ifdef __ANDROID__
#include "hexagon_stubapi.h"
#include <dlfcn.h>
#include <dmlc/logging.h>
#include <stdint.h>
#include <sys/stat.h>
#include "hexagon_target_log.h"
namespace tvm {
namespace runtime {
namespace hexagon {
StubAPI::StubAPI() {
struct stat sb;
if (!stat("/dev/subsys_cdsp", &sb)) {
enable_domains_ = true;
TVM_LOGD("CDSP subsystem present");
} else if (!stat("/dev/subsys_adsp", &sb)) {
enable_domains_ = false;
TVM_LOGD("ADSP subsystem present");
}
constexpr auto domain_lib_name = "libtvm_hexagon_remote_stub.so";
constexpr auto nondomain_lib_name = "libtvm_hexagon_remote_nd_stub.so";
const char* lib_name =
enable_domains_ ? domain_lib_name : nondomain_lib_name;
CHECK(lib_handle_ = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL));
#define RESOLVE(fn) p##fn##_ = GetSymbol<fn##_t*>(#fn)
if (enable_domains_) {
RESOLVE(tvm_hexagon_remote_load_library);
RESOLVE(tvm_hexagon_remote_release_library);
RESOLVE(tvm_hexagon_remote_get_symbol);
RESOLVE(tvm_hexagon_remote_kernel);
RESOLVE(tvm_hexagon_remote_open);
RESOLVE(tvm_hexagon_remote_close);
RESOLVE(tvm_hexagon_remote_alloc_vtcm);
RESOLVE(tvm_hexagon_remote_free_vtcm);
RESOLVE(tvm_hexagon_remote_call_mmap64);
} else {
RESOLVE(tvm_hexagon_remote_nd_load_library);
RESOLVE(tvm_hexagon_remote_nd_release_library);
RESOLVE(tvm_hexagon_remote_nd_get_symbol);
RESOLVE(tvm_hexagon_remote_nd_kernel);
RESOLVE(tvm_hexagon_remote_nd_open);
RESOLVE(tvm_hexagon_remote_nd_call_mmap64);
}
RESOLVE(rpcmem_init);
RESOLVE(rpcmem_deinit);
RESOLVE(rpcmem_alloc);
RESOLVE(rpcmem_free);
RESOLVE(rpcmem_to_fd);
#undef RESOLVE
}
StubAPI::~StubAPI() {
if (lib_handle_) dlclose(lib_handle_);
}
template <typename T>
T StubAPI::GetSymbol(const char* sym) {
if (!lib_handle_) {
TVM_LOGE("error looking up symbol \"%s\": library not loaded", sym);
return nullptr;
}
dlerror(); // Clear any previous errror conditions.
if (T ret = reinterpret_cast<T>(dlsym(lib_handle_, sym))) {
return ret;
}
const char* err = dlerror();
const char* err_txt = err ? err : "symbol not found";
TVM_LOGE("error looking up symbol \"%s\": %s", sym, err_txt);
return nullptr;
}
const StubAPI* StubAPI::Global() {
static const StubAPI stub_api;
return &stub_api;
}
} // namespace hexagon
} // namespace runtime
} // namespace tvm
#endif // __ANDROID__
/*
* 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_TARGET_HEXAGON_TARGET_LOG_H_
#define TVM_RUNTIME_HEXAGON_TARGET_HEXAGON_TARGET_LOG_H_
#ifdef __ANDROID__
#include <android/log.h>
#define TVM_LOGV(...) \
__android_log_print(ANDROID_LOG_VERBOSE, "TVM", ##__VA_ARGS__)
#define TVM_LOGD(...) \
__android_log_print(ANDROID_LOG_DEBUG, "TVM", ##__VA_ARGS__)
#define TVM_LOGI(...) \
__android_log_print(ANDROID_LOG_INFO, "TVM", ##__VA_ARGS__)
#define TVM_LOGW(...) \
__android_log_print(ANDROID_LOG_WARN, "TVM", ##__VA_ARGS__)
#define TVM_LOGE(...) \
__android_log_print(ANDROID_LOG_ERROR, "TVM", ##__VA_ARGS__)
#define TVM_LOGF(...) \
__android_log_print(ANDROID_LOG_FATAL, "TVM", ##__VA_ARGS__)
#endif // __ANDROID__
#endif // TVM_RUNTIME_HEXAGON_TARGET_HEXAGON_TARGET_LOG_H_
/*
* 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 "../source/codegen_source_base.h"
namespace tvm {
namespace runtime {
Module HexagonModuleCreate(std::string data, std::string fmt,
std::unordered_map<std::string, FunctionInfo> fmap,
std::string asm_str, std::string obj_str,
std::string ir_str, std::string bc_str,
const std::set<std::string>& packed_c_abi) {
LOG(WARNING) << "Hexagon runtime is not enabled, return a source module...";
return codegen::DeviceSourceModuleCreate(data, fmt, fmap, "hex");
}
} // namespace runtime
} // namespace tvm
......@@ -48,8 +48,8 @@ TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
/*!
* \brief Construct a Target node from the given name and options.
* \param target_name The major target name. Should be one of
* {"aocl", "aocl_sw_emu", "c", "cuda", "ext_dev", "hybrid", "llvm", "metal",
* "nvptx", "opencl", "opengl", "rocm", "sdaccel", "stackvm", "vulkan"}
* {"aocl", "aocl_sw_emu", "c", "cuda", "ext_dev", "hexagon", "hybrid", "llvm",
* "metal", "nvptx", "opencl", "opengl", "rocm", "sdaccel", "stackvm", "vulkan"}
* \param options Additional options appended to the target
* \return The constructed Target
*/
......@@ -136,6 +136,9 @@ Target CreateTarget(const std::string& target_name,
t->device_type = kDLExtDev;
} else if (target_name == "hybrid") {
t->device_type = kDLCPU;
} else if (target_name == "hexagon") {
t->keys_array.push_back(tir::StringImmNode::make("hexagon"));
t->device_type = kDLHexagon;
} else {
LOG(ERROR) << "Unknown target name " << target_name;
return target::stackvm();
......@@ -336,6 +339,10 @@ Target stackvm(const std::vector<std::string>& options) {
Target ext_dev(const std::vector<std::string>& options) {
return CreateTarget("ext_dev", options);
}
Target hexagon(const std::vector<std::string>& options) {
return CreateTarget("hexagon", options);
}
} // namespace target
BuildConfig BuildConfig::Create() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment