Skip to content

Commit

Permalink
[llvm] [aot] Add LLVM to CAPI part 4: Enabled C-API tests on CI & Add…
Browse files Browse the repository at this point in the history
…ed C-API tests for CPU backend (#5435)

* [build] Enabled C-API compilation on CI

* Fixed minor issue

* Enabled CAPI compilation on windows build bots

* Fixed minor issue

* Removed LLVM-15 test on windows

* [llvm] [aot] Add LLVM to CAPI part 4: Enabled C-API tests on CI & Add basic C-API interface test cases

* Removed debug info

* Fixed CI issues

* Added C-API tests for LLVM-CPU backend
  • Loading branch information
jim19930609 committed Jul 18, 2022
1 parent 98d5075 commit 08f6d60
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 31 deletions.
1 change: 1 addition & 0 deletions .github/workflows/scripts/unix_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ check_in_docker() {
export TI_SKIP_VERSION_CHECK=ON
export TI_CI=1
export TI_IN_DOCKER=$(check_in_docker)
export LD_LIBRARY_PATH=$PWD/build/:$LD_LIBRARY_PATH

if [[ "$TI_IN_DOCKER" == "true" ]]; then
source $HOME/miniconda/etc/profile.d/conda.sh
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,7 @@ option(TI_WITH_C_API "build taichi runtime c-api library" OFF)

if (TI_WITH_C_API)
include(cmake/TaichiCAPI.cmake)
if (TI_BUILD_TESTS)
include(cmake/TaichiCAPITests.cmake)
endif()
endif()
21 changes: 15 additions & 6 deletions c_api/src/taichi_core_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ taichi::lang::DeviceAllocation Runtime::allocate_memory(
return devalloc;
}

void Runtime::deallocate_memory(TiMemory devmem) {
this->get().dealloc_memory(devmem2devalloc(*this, devmem));
}

AotModule::AotModule(Runtime &runtime,
std::unique_ptr<taichi::lang::aot::Module> &&aot_module)
: runtime_(&runtime), aot_module_(std::move(aot_module)) {
Expand Down Expand Up @@ -51,23 +55,28 @@ Runtime &AotModule::runtime() {
TiRuntime ti_create_runtime(TiArch arch) {
switch (arch) {
#ifdef TI_WITH_VULKAN
case TI_ARCH_VULKAN:
case TI_ARCH_VULKAN: {
return (TiRuntime)(static_cast<Runtime *>(new VulkanRuntimeOwned));
}
#endif // TI_WITH_VULKAN
#ifdef TI_WITH_LLVM
case TI_ARCH_X64:
case TI_ARCH_X64: {
return (TiRuntime)(static_cast<Runtime *>(
new capi::LlvmRuntime(taichi::Arch::x64)));
case TI_ARCH_ARM64:
}
case TI_ARCH_ARM64: {
return (TiRuntime)(static_cast<Runtime *>(
new capi::LlvmRuntime(taichi::Arch::arm64)));
case TI_ARCH_CUDA:
}
case TI_ARCH_CUDA: {
return (TiRuntime)(static_cast<Runtime *>(
new capi::LlvmRuntime(taichi::Arch::cuda)));
}
#endif // TI_WITH_LLVM
default:
default: {
TI_WARN("ignored attempt to create runtime on unknown arch");
return TI_NULL_HANDLE;
}
}
return TI_NULL_HANDLE;
}
Expand Down Expand Up @@ -123,7 +132,7 @@ void ti_free_memory(TiRuntime runtime, TiMemory devmem) {
}

Runtime *runtime2 = (Runtime *)runtime;
runtime2->get().dealloc_memory(devmem2devalloc(*runtime2, devmem));
runtime2->deallocate_memory(devmem);
}

void *ti_map_memory(TiRuntime runtime, TiMemory devmem) {
Expand Down
2 changes: 2 additions & 0 deletions c_api/src/taichi_core_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class Runtime {
virtual TiAotModule load_aot_module(const char *module_path) = 0;
virtual taichi::lang::DeviceAllocation allocate_memory(
const taichi::lang::Device::AllocParams &params);
virtual void deallocate_memory(TiMemory devmem);

virtual void buffer_copy(const taichi::lang::DevicePtr &dst,
const taichi::lang::DevicePtr &src,
size_t size) = 0;
Expand Down
28 changes: 25 additions & 3 deletions c_api/src/taichi_llvm_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@

#ifdef TI_WITH_LLVM

#include "taichi/program/compile_config.h"
#include "taichi/runtime/llvm/llvm_runtime_executor.h"
#include "taichi/runtime/cpu/aot_module_loader_impl.h"

#ifdef TI_WITH_CUDA
#include "taichi/runtime/cuda/aot_module_loader_impl.h"
#endif

namespace capi {

LlvmRuntime::LlvmRuntime(taichi::Arch arch) : Runtime(arch) {
taichi::lang::CompileConfig cfg;
cfg.arch = arch;
executor_ = std::make_unique<taichi::lang::LlvmRuntimeExecutor>(cfg, nullptr);
cfg_ = std::make_unique<taichi::lang::CompileConfig>();
cfg_->arch = arch;

executor_ =
std::make_unique<taichi::lang::LlvmRuntimeExecutor>(*cfg_.get(), nullptr);

taichi::lang::Device *compute_device = executor_->get_compute_device();
memory_pool_ =
Expand Down Expand Up @@ -49,6 +55,18 @@ taichi::lang::DeviceAllocation LlvmRuntime::allocate_memory(
llvm_runtime, result_buffer});
}

void LlvmRuntime::deallocate_memory(TiMemory devmem) {
taichi::lang::CompileConfig *config = executor_->get_config();
if (taichi::arch_is_cpu(config->arch)) {
// For memory allocated through Device::allocate_memory_runtime(),
// the corresponding Device::deallocate_memory() interface has not been
// implemented yet...
TI_NOT_IMPLEMENTED;
}

Runtime::deallocate_memory(devmem);
}

TiAotModule LlvmRuntime::load_aot_module(const char *module_path) {
auto *config = executor_->get_config();
std::unique_ptr<taichi::lang::aot::Module> aot_module{nullptr};
Expand All @@ -60,11 +78,15 @@ TiAotModule LlvmRuntime::load_aot_module(const char *module_path) {
aot_module = taichi::lang::cpu::make_aot_module(aot_params);

} else {
#ifdef TI_WITH_CUDA
TI_ASSERT(config->arch == taichi::Arch::cuda);
taichi::lang::cuda::AotModuleParams aot_params;
aot_params.executor_ = executor_.get();
aot_params.module_path = module_path;
aot_module = taichi::lang::cuda::make_aot_module(aot_params);
#else
TI_NOT_IMPLEMENTED;
#endif
}

// Insert LLVMRuntime to RuntimeContext
Expand Down
3 changes: 3 additions & 0 deletions c_api/src/taichi_llvm_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace taichi {
namespace lang {
class LlvmRuntimeExecutor;
class MemoryPool;
struct CompileConfig;
} // namespace lang
} // namespace taichi

Expand All @@ -23,6 +24,7 @@ class LlvmRuntime : public Runtime {
TiAotModule load_aot_module(const char *module_path) override;
taichi::lang::DeviceAllocation allocate_memory(
const taichi::lang::Device::AllocParams &params) override;
void deallocate_memory(TiMemory devmem) override;

void buffer_copy(const taichi::lang::DevicePtr &dst,
const taichi::lang::DevicePtr &src,
Expand All @@ -36,6 +38,7 @@ class LlvmRuntime : public Runtime {
taichi::uint64 *result_buffer{nullptr};
std::unique_ptr<taichi::lang::LlvmRuntimeExecutor> executor_{nullptr};
std::unique_ptr<taichi::lang::MemoryPool> memory_pool_{nullptr};
std::unique_ptr<taichi::lang::CompileConfig> cfg_{nullptr};
};

} // namespace capi
Expand Down
51 changes: 51 additions & 0 deletions c_api/tests/c_api_interface_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "gtest/gtest.h"
#include "taichi/taichi_core.h"

TEST(CapiDryRun, Runtime) {
{
// CPU Runtime
TiArch arch = TiArch::TI_ARCH_X64;
TiRuntime runtime = ti_create_runtime(arch);
ti_destroy_runtime(runtime);
}
}

TEST(CapiDryRun, MemoryAllocation) {
TiMemoryAllocateInfo alloc_info;
alloc_info.size = 100;
alloc_info.host_write = false;
alloc_info.host_read = false;
alloc_info.export_sharing = false;
alloc_info.usage = TiMemoryUsageFlagBits::TI_MEMORY_USAGE_STORAGE_BIT;

{
// CPU Runtime
TiArch arch = TiArch::TI_ARCH_X64;
TiRuntime runtime = ti_create_runtime(arch);

ti_allocate_memory(runtime, &alloc_info);

// Unfortunately, memory deallocation for
// CPU backend has not been implemented yet...

ti_destroy_runtime(runtime);
}
}

TEST(CapiDryRun, CpuAotModule) {
const auto folder_dir = getenv("TAICHI_AOT_FOLDER_PATH");

std::stringstream aot_mod_ss;
aot_mod_ss << folder_dir;

{
// CPU Runtime
TiArch arch = TiArch::TI_ARCH_X64;
TiRuntime runtime = ti_create_runtime(arch);

TiAotModule aot_mod = ti_load_aot_module(runtime, aot_mod_ss.str().c_str());
ti_destroy_aot_module(aot_mod);

ti_destroy_runtime(runtime);
}
}
9 changes: 4 additions & 5 deletions cmake/TaichiCAPI.cmake
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
cmake_minimum_required(VERSION 3.0)




set(TAICHI_C_API_NAME taichi_c_api)

file(GLOB_RECURSE C_API_SOURCE "c_api/src/*.cpp")
add_library(${TAICHI_C_API_NAME} SHARED ${C_API_SOURCE})
target_link_libraries(${TAICHI_C_API_NAME} PRIVATE taichi_isolated_core)

set(C_API_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build")
set_target_properties(${TAICHI_C_API_NAME} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build")
LIBRARY_OUTPUT_DIRECTORY ${C_API_OUTPUT_DIRECTORY}
ARCHIVE_OUTPUT_DIRECTORY ${C_API_OUTPUT_DIRECTORY})

target_include_directories(${TAICHI_C_API_NAME}
PUBLIC
Expand Down
27 changes: 27 additions & 0 deletions cmake/TaichiCAPITests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.0)

set(C_API_TESTS_NAME taichi_c_api_tests)
if (WIN32)
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()

# TODO(#2195):
# 1. "cpp" -> "cpp_legacy", "cpp_new" -> "cpp"
# 2. Re-implement the legacy CPP tests using googletest
file(GLOB_RECURSE TAICHI_C_API_TESTS_SOURCE
"c_api/tests/*.cpp")

add_executable(${C_API_TESTS_NAME} ${TAICHI_C_API_TESTS_SOURCE})

target_link_libraries(${C_API_TESTS_NAME} PRIVATE taichi_c_api)
target_link_libraries(${C_API_TESTS_NAME} PRIVATE gtest_main)

target_include_directories(${C_API_TESTS_NAME}
PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/c_api/include
)

add_test(NAME ${C_API_TESTS_NAME} COMMAND ${C_API_TESTS_NAME})
43 changes: 26 additions & 17 deletions tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,17 @@
import tempfile
import warnings

from test_utils import __aot_test_cases, print_aot_test_guide
from test_utils import (__aot_test_cases, __capi_aot_test_cases,
print_aot_test_guide)

import taichi as ti


def _run_cpp_test(gtest_option="", extra_env=None):
def _run_cpp_test(test_filename, build_dir, gtest_option="", extra_env=None):
ti.reset()
print("Running C++ tests...")
ti_lib_dir = os.path.join(ti.__path__[0], '_lib', 'runtime')

curr_dir = os.path.dirname(os.path.abspath(__file__))
if platform.system() == "Windows":
cpp_test_filename = 'taichi_cpp_tests.exe'
build_dir = os.path.join(curr_dir, '../bin')
else:
cpp_test_filename = 'taichi_cpp_tests'
build_dir = os.path.join(curr_dir, '../build')

fullpath = os.path.join(build_dir, cpp_test_filename)
fullpath = os.path.join(build_dir, test_filename)

if os.path.exists(fullpath):
env_copy = os.environ.copy()
Expand All @@ -38,9 +30,9 @@ def _run_cpp_test(gtest_option="", extra_env=None):
subprocess.check_call(cmd, env=env_copy, cwd=build_dir)


def _test_cpp_aot():
def _test_cpp_aot(test_filename, build_dir, test_info):
tests_visited = []
for cpp_test_name, (python_rpath, args) in __aot_test_cases.items():
for cpp_test_name, (python_rpath, args) in test_info.items():
# Temporary folder will be removed upon handle destruction
temp_handle = tempfile.TemporaryDirectory()
temp_folderpath = temp_handle.name
Expand All @@ -59,19 +51,36 @@ def _test_cpp_aot():
env=env_copy)

# Run AOT C++ codes
_run_cpp_test(f"--gtest_filter={cpp_test_name}", extra_env)
_run_cpp_test(test_filename, build_dir,
f"--gtest_filter={cpp_test_name}", extra_env)
tests_visited.append(cpp_test_name)

exclude_tests_cmd = "--gtest_filter=-" + ":".join(tests_visited)
return exclude_tests_cmd


def _test_cpp():
curr_dir = os.path.dirname(os.path.abspath(__file__))
if platform.system() == "Windows":
cpp_test_filename = 'taichi_cpp_tests.exe'
capi_test_filename = 'taichi_c_api_tests.exe'
build_dir = os.path.join(curr_dir, '../bin')
else:
cpp_test_filename = 'taichi_cpp_tests'
capi_test_filename = 'taichi_c_api_tests'
build_dir = os.path.join(curr_dir, '../build')

# Run C-API test cases
exclude_tests_cmd = _test_cpp_aot(capi_test_filename, build_dir,
__capi_aot_test_cases)
_run_cpp_test(capi_test_filename, build_dir, exclude_tests_cmd)

# Run AOT test cases
exclude_tests_cmd = _test_cpp_aot()
exclude_tests_cmd = _test_cpp_aot(cpp_test_filename, build_dir,
__aot_test_cases)

# Run rest of the cpp tests
_run_cpp_test(exclude_tests_cmd)
_run_cpp_test(cpp_test_filename, build_dir, exclude_tests_cmd)


def _test_python(args):
Expand Down
5 changes: 5 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
[os.path.join('cpp', 'aot', 'mpm88_graph_aot.py'), "--arch=vulkan"],
}

__capi_aot_test_cases = {
"CapiDryRun.CpuAotModule":
[os.path.join('cpp', 'aot', 'llvm', 'kernel_aot_test.py'), "--arch=cpu"],
}


def print_aot_test_guide():
message = f"""
Expand Down

0 comments on commit 08f6d60

Please sign in to comment.