Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Hexagon] Add support for on-device unit testing using gtest #11145

Merged
merged 20 commits into from May 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion CMakeLists.txt
Expand Up @@ -43,6 +43,7 @@ tvm_option(ROCM_PATH "The path to rocm" /opt/rocm)
tvm_option(USE_HEXAGON "Build with Hexagon support" OFF)
tvm_option(USE_HEXAGON_SDK "Path to the Hexagon SDK root (required for Hexagon support)" /path/to/sdk)
tvm_option(USE_HEXAGON_RPC "Enable Hexagon RPC using minRPC implementation over Android." OFF)
tvm_option(USE_HEXAGON_GTEST "Path to Hexagon specific gtest version for runtime cpp tests." /path/to/hexagon/gtest)
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)
Expand Down Expand Up @@ -598,6 +599,15 @@ endif()
target_link_libraries(tvm PRIVATE ${TVM_LINKER_LIBS} ${TVM_RUNTIME_LINKER_LIBS})
target_link_libraries(tvm_runtime PRIVATE ${TVM_RUNTIME_LINKER_LIBS})

if(BUILD_FOR_HEXAGON AND DEFINED USE_HEXAGON_GTEST AND EXISTS ${USE_HEXAGON_GTEST})
adstraw marked this conversation as resolved.
Show resolved Hide resolved
include(FetchContent)
FetchContent_Declare(googletest SOURCE_DIR "${USE_HEXAGON_GTEST}")
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
target_link_libraries(tvm_runtime PUBLIC gtest)
adstraw marked this conversation as resolved.
Show resolved Hide resolved
include_directories("${USE_HEXAGON_GTEST}/include")
endif()

# Set flags for clang
include(cmake/modules/ClangFlags.cmake)
set(CRC16_INCLUDE_PATH "3rdparty/libcrc/include")
Expand Down Expand Up @@ -634,7 +644,6 @@ if(GTEST_FOUND)
tvm_file_glob(GLOB_RECURSE TEST_SRCS tests/cpp/*.cc)
add_executable(cpptest ${TEST_SRCS})
# include runtime files for unit testing
target_include_directories(cpptest PUBLIC "src/runtime")
target_link_libraries(cpptest PRIVATE ${TVM_TEST_LIBRARY_NAME} GTest::GTest GTest::Main GTest::gmock pthread dl)
set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_ALL 1)
set_target_properties(cpptest PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
Expand All @@ -649,6 +658,9 @@ add_custom_target(runtime DEPENDS tvm_runtime)
# Installation rules
install(TARGETS tvm EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
install(TARGETS tvm_runtime EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
if(BUILD_FOR_HEXAGON AND DEFINED USE_HEXAGON_GTEST AND EXISTS ${USE_HEXAGON_GTEST})
install(TARGETS gtest EXPORT ${PROJECT_NAME}Targets DESTINATION lib${LIB_SUFFIX})
endif()

if (INSTALL_DEV)
install(
Expand Down
13 changes: 13 additions & 0 deletions apps/hexagon_api/CMakeLists.txt
Expand Up @@ -13,6 +13,7 @@ include(ExternalProject)
# USE_HEXAGON_TOOLCHAIN (Path to Hexagon toolchain ending with "Tools")
# Optional variable:
# USE_OUTPUT_BINARY_DIR (Path to copy the output binaries to)
# USE_HEXAGON_GTEST (Path to Hexagon specific gtest version)

set(TVM_SOURCE_DIR "${CMAKE_SOURCE_DIR}/../..")

Expand All @@ -23,6 +24,15 @@ else()
endif()
file(MAKE_DIRECTORY ${HEXAGON_API_BINARY_DIR})

if(DEFINED USE_HEXAGON_GTEST)
if(EXISTS ${USE_HEXAGON_GTEST})
message(STATUS "Found Hexagon gtest at ${USE_HEXAGON_GTEST}")
else()
message(WARNING "Could not find Hexagon gtest at ${USE_HEXAGON_GTEST}. Disabling Hexagon gtest support.")
unset(USE_HEXAGON_GTEST)
endif()
endif()

# Build X86 binaries:
# - tvm_rpc_x86

Expand Down Expand Up @@ -109,6 +119,9 @@ ExternalProject_Add(hexagon_tvm_runtime_rpc
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-DUSE_ALTERNATIVE_LINKER=OFF"
"-DUSE_CUSTOM_LOGGING=ON"
if(DEFINED USE_HEXAGON_GTEST)
"-DUSE_HEXAGON_GTEST=${USE_HEXAGON_GTEST}"
endif()
INSTALL_COMMAND ""
BUILD_ALWAYS ON
)
Expand Down
24 changes: 15 additions & 9 deletions cmake/modules/Hexagon.cmake
Expand Up @@ -84,9 +84,6 @@ if(NOT USE_HEXAGON)
if(BUILD_FOR_HOST)
list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc)
endif()
list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon_buffer.cc)
list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon_common.cc)
list(APPEND RUNTIME_SRCS src/runtime/hexagon/hexagon_user_dma.cc)
return()
endif()

Expand Down Expand Up @@ -119,14 +116,23 @@ function(add_hexagon_wrapper_paths)
link_directories("${HEXAGON_TOOLCHAIN}/lib/iss")
endfunction()


# Common sources for TVM runtime with Hexagon support
file_glob_append(RUNTIME_HEXAGON_SRCS
"${TVMRT_SOURCE_DIR}/hexagon/*.cc"
)

if(BUILD_FOR_HEXAGON OR USE_HEXAGON_RPC)
# Common sources for TVM runtime with Hexagon support
file_glob_append(RUNTIME_HEXAGON_SRCS
"${TVMRT_SOURCE_DIR}/hexagon/*.cc"
)
else()
file_glob_append(RUNTIME_HEXAGON_SRCS
"${TVMRT_SOURCE_DIR}/hexagon/hexagon_module.cc"
)
endif()
Comment on lines +119 to +128
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part disables Hexagon runtime when building for x86. Please revert this.

Nevermind. It was an error on my side. Sorry for the noise.


if(BUILD_FOR_HEXAGON)
if(DEFINED USE_HEXAGON_GTEST AND EXISTS ${USE_HEXAGON_GTEST})
file_glob_append(RUNTIME_HEXAGON_SRCS
"${CMAKE_SOURCE_DIR}/tests/cpp-runtime/hexagon/*.cc"
)
endif()
get_hexagon_sdk_property("${USE_HEXAGON_SDK}" "${USE_HEXAGON_ARCH}"
SDK_INCLUDE SDK_INCLUDE_DIRS
QURT_INCLUDE QURT_INCLUDE_DIRS
Expand Down
1 change: 1 addition & 0 deletions cmake/modules/LibInfo.cmake
Expand Up @@ -74,6 +74,7 @@ function(add_lib_info src_file)
TVM_INFO_USE_HEXAGON="${USE_HEXAGON}"
TVM_INFO_USE_HEXAGON_RPC="${USE_HEXAGON_RPC}"
TVM_INFO_USE_HEXAGON_SDK="${USE_HEXAGON_SDK}"
TVM_INFO_USE_HEXAGON_GTEST="${USE_HEXAGON_GTEST}"
TVM_INFO_USE_IOS_RPC="${USE_IOS_RPC}"
TVM_INFO_USE_KHRONOS_SPIRV="${USE_KHRONOS_SPIRV}"
TVM_INFO_USE_LIBBACKTRACE="${USE_LIBBACKTRACE}"
Expand Down
25 changes: 5 additions & 20 deletions src/runtime/hexagon/hexagon_buffer.cc
Expand Up @@ -52,26 +52,15 @@ struct Allocation {

struct DDRAllocation : public Allocation {
DDRAllocation(size_t nbytes, size_t alignment) : Allocation(nbytes, alignment) {
#ifdef _WIN32
data_ = _aligned_malloc(nbytes, alignment);
CHECK(data_ != nullptr);
#else
int ret = posix_memalign(&data_, alignment, nbytes);
CHECK_EQ(ret, 0);
#endif
}
~DDRAllocation() {
#ifdef _WIN32
_aligned_free(data_);
#else
free(data_);
#endif
}
~DDRAllocation() { free(data_); }
};

#if defined(__hexagon__)
struct VTCMAllocation : public Allocation {
VTCMAllocation(size_t nbytes, size_t alignment) : Allocation(nbytes, alignment) {
#if defined(__hexagon__)
compute_res_attr_t res_info;
HEXAGON_SAFE_CALL(HAP_compute_res_attr_init(&res_info));

Expand All @@ -94,20 +83,16 @@ struct VTCMAllocation : public Allocation {
LOG(ERROR) << "ERROR: Unable to acquire requeisted resource.";
return;
}
// LOG(INFO) << "VTCMAllocation() - Context ID: " << context_id_ << ", VTCM ptr: " << data_;
#endif
}
~VTCMAllocation() {
// LOG(INFO) << "~VTCMAllocation() - Context ID: " << context_id_ << ", VTCM ptr: " << data_;
#if defined(__hexagon__)
HEXAGON_SAFE_CALL(HAP_compute_res_release(context_id_));
data_ = nullptr;
#endif
}
unsigned int context_id_{0};
};
#else
struct VTCMAllocation : public DDRAllocation {
VTCMAllocation(size_t nbytes, size_t alignment) : DDRAllocation(nbytes, alignment) {}
};
#endif

template <HexagonBuffer::StorageScope S>
std::unique_ptr<Allocation> Allocator(size_t nbytes, size_t alignment);
Expand Down
13 changes: 1 addition & 12 deletions src/runtime/hexagon/hexagon_user_dma.cc
Expand Up @@ -68,14 +68,10 @@ int hexagon_user_dma_1d_sync_helper(void* dst, void* src, uint32_t length) {

void* dma_desc = nullptr;

#ifdef _WIN32
dma_desc = _aligned_malloc(DMA_DESC_2D_SIZE, DMA_DESC_2D_SIZE);
#else
int ret = posix_memalign(&dma_desc, DMA_DESC_2D_SIZE, DMA_DESC_2D_SIZE);
if (ret) {
return DMA_FAILURE;
}
#endif

if (!dma_desc) {
return DMA_FAILURE;
Expand All @@ -98,20 +94,13 @@ int hexagon_user_dma_1d_sync_helper(void* dst, void* src, uint32_t length) {
unsigned int status = dmwait() & DM0_STATUS_MASK;
unsigned int done = dma_desc_get_done(dma_desc);

#ifdef _WIN32
_aligned_free(dma_desc);
#else
free(dma_desc);
#endif

if (status == DM0_STATUS_IDLE && done == DESC_DONE_COMPLETE) {
return DMA_SUCCESS;
}
return DMA_FAILURE;
#else
memcpy(dst, src, length);
return DMA_SUCCESS;
#endif
return DMA_FAILURE;
}

int hexagon_user_dma_1d_sync(void* dst, void* src, uint32_t length) {
Expand Down
5 changes: 5 additions & 0 deletions src/support/libinfo.cc
Expand Up @@ -67,6 +67,10 @@
#define TVM_INFO_USE_HEXAGON_SDK "NOT-FOUND"
#endif

#ifndef TVM_INFO_USE_HEXAGON_GTEST
#define TVM_INFO_USE_HEXAGON_GTEST "NOT-FOUND"
#endif

#ifndef TVM_INFO_USE_RPC
#define TVM_INFO_USE_RPC "NOT-FOUND"
#endif
Expand Down Expand Up @@ -267,6 +271,7 @@ TVM_DLL Map<String, String> GetLibInfo() {
{"USE_HEXAGON", TVM_INFO_USE_HEXAGON},
{"USE_HEXAGON_RPC", TVM_INFO_USE_HEXAGON_RPC},
{"USE_HEXAGON_SDK", TVM_INFO_USE_HEXAGON_SDK},
{"USE_HEXAGON_GTEST", TVM_INFO_USE_HEXAGON_GTEST},
{"USE_IOS_RPC", TVM_INFO_USE_IOS_RPC},
{"USE_KHRONOS_SPIRV", TVM_INFO_USE_KHRONOS_SPIRV},
{"USE_LIBBACKTRACE", TVM_INFO_USE_LIBBACKTRACE},
Expand Down
Expand Up @@ -18,9 +18,10 @@
*/

#include <gtest/gtest.h>
#include <hexagon/hexagon_buffer.h>
#include <tvm/runtime/container/optional.h>

#include "../src/runtime/hexagon/hexagon_buffer.h"

using namespace tvm::runtime;
using namespace tvm::runtime::hexagon;

Expand Down
60 changes: 60 additions & 0 deletions tests/cpp-runtime/hexagon/run_all_tests.cc
@@ -0,0 +1,60 @@
/*
* 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 <gtest/gtest.h>
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>

#include <string>
#include <vector>

#include "../src/support/utils.h"

namespace tvm {
namespace runtime {
namespace hexagon {

TVM_REGISTER_GLOBAL("hexagon.run_all_tests").set_body([](TVMArgs args, TVMRetValue* rv) {
// gtest args are passed into this packed func as a singular string
// split gtest args using <space> delimiter and build argument vector
std::vector<std::string> parsed_args = tvm::support::Split(args[0], ' ');
std::vector<char*> argv;

// add executable name
argv.push_back(const_cast<char*>("hexagon_run_all_tests"));

// add parsed arguments
for (int i = 0; i < parsed_args.size(); ++i) {
argv.push_back(const_cast<char*>(parsed_args[i].data()));
}

// end of parsed arguments
argv.push_back(nullptr);

// set argument count
int argc = argv.size() - 1;

// initialize gtest with arguments and run
::testing::InitGoogleTest(&argc, argv.data());
*rv = RUN_ALL_TESTS();
});

} // namespace hexagon
} // namespace runtime
} // namespace tvm
42 changes: 42 additions & 0 deletions tests/python/contrib/test_hexagon/unit_tests.py
@@ -0,0 +1,42 @@
# 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.

import pytest
import numpy as np
from tvm.contrib.hexagon.build import HexagonLauncher
from .conftest import requires_hexagon_toolchain


@requires_hexagon_toolchain
def test_cache_read_write_2d(hexagon_session):
# arguments to pass to gtest
# e.g.
# 1) to run all tests use:
# gtest_args = ""
# 2) to run all tests with "foo" in their name twice use:
# gtest_args = "--gtest_repeat=2 --gtest_filter=*foo*"
gtest_args = ""
try:
func = hexagon_session._rpc.get_function("hexagon.run_all_tests")
result = func(gtest_args)
except:
print(
"This test requires the USE_HEXAGON_GTEST cmake flag to be specified with a path to a Hexagon gtest version normally located at /path/to/hexagon/sdk/utils/googletest/gtest"
)
result = 1

np.testing.assert_equal(result, 0)
3 changes: 2 additions & 1 deletion tests/scripts/task_build_hexagon_api.sh
Expand Up @@ -33,6 +33,7 @@ cmake -DANDROID_ABI=arm64-v8a \
-DUSE_HEXAGON_ARCH=v68 \
-DUSE_HEXAGON_SDK="${HEXAGON_SDK_PATH}" \
-DUSE_HEXAGON_TOOLCHAIN="${HEXAGON_TOOLCHAIN}" \
-DUSE_OUTPUT_BINARY_DIR="${output_binary_directory}" ..
-DUSE_OUTPUT_BINARY_DIR="${output_binary_directory}" \
-DUSE_HEXAGON_GTEST="${HEXAGON_SDK_PATH}/utils/googletest/gtest" ..

make -j$(nproc)