Skip to content

Commit

Permalink
[Hexagon] Add support for on-device unit testing using gtest (apache#…
Browse files Browse the repository at this point in the history
…11145)

* link gtest to tvm runtime

* first test running!

* HexagonBuffer tests running in sim

* move to new tests directory

* use USE_HEXAGON_SDK

* add python frontend for Hexagon unit tests

* clean up after rebase

* isolate cmake changes to Hexagon

* add gtest init with arguments

* add hexagon sources only if building for Hexagon; remove workaround

* format & lint

* fix Hexagon build error

* remove x86 implementation and win32 code

* check if hexagon gtest path exists before linking

* make USE_HEXAGON_GTEST an optional cmake param

* turn on Hexagon gtest in Hexagon CI

* Hexagon unit tests should fail if run without proper gtest linkage

* add tvm option; move Hexagon tests to test/cpp-runtime/hexagon

* add libinfo

* trigger ci
  • Loading branch information
adstraw authored and juda committed Jun 21, 2022
1 parent 0ee8ad4 commit 5a40f23
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 44 deletions.
14 changes: 13 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
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})
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)
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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()

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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)

0 comments on commit 5a40f23

Please sign in to comment.