Skip to content

Commit

Permalink
Add GHA workflow to test packaging and usage on Ubuntu
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreinking committed May 15, 2021
1 parent b059989 commit ddc5893
Show file tree
Hide file tree
Showing 11 changed files with 439 additions and 0 deletions.
51 changes: 51 additions & 0 deletions .github/workflows/packaging.yml
@@ -0,0 +1,51 @@
name: Packaging
on: [ 'pull_request' ]
jobs:
package-ubuntu:
name: Package for Ubuntu
runs-on: ubuntu-20.04
env:
CMAKE_CXX_COMPILER_LAUNCHER: ccache
CMAKE_C_COMPILER_LAUNCHER: ccache
LLVM_ROOT: /usr/lib/llvm-11
steps:
- name: Install dependencies
run: |
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \
| gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
sudo apt update
sudo apt install cmake ninja-build doxygen ccache
sudo apt install llvm-11-dev liblld-11-dev clang-11 libclang-11-dev libjpeg-dev libpng-dev
sudo apt install lintian dpkg-dev
- name: Check out sources
uses: actions/checkout@v2
- name: Set up ccache
uses: hendrikmuhs/ccache-action@v1
- name: Run Ubuntu packaging script
run: ./packaging/ubuntu/package.sh . ubuntu
- name: Upload packages
uses: actions/upload-artifact@v2
with:
name: packages
path: ubuntu/*.deb
test-ubuntu:
name: Test Ubuntu package
needs: package-ubuntu
runs-on: ubuntu-20.04
steps:
# Specifically use the CMake version that comes with Ubuntu.
- name: Install dependencies
run: sudo apt install cmake ninja-build libc6-dev-arm64-cross gcc-aarch64-linux-gnu g++-aarch64-linux-gnu qemu-user
- name: Check out sources
uses: actions/checkout@v2
- name: Download Halide Ubuntu packages
uses: actions/download-artifact@v2
with:
name: packages
- name: Install Halide Ubuntu packages
run: sudo apt install ./*.deb
- name: Test integration
run: |
cmake -S test/integration -B build
cd build && ctest -j$(nproc) --output-on-failure
133 changes: 133 additions & 0 deletions test/integration/CMakeLists.txt
@@ -0,0 +1,133 @@
cmake_minimum_required(VERSION 3.16)
project(integration_tests NONE)

enable_testing()

##
# Single-linkage JIT integration tests.
##

foreach (bsl IN ITEMS "" "-DBUILD_SHARED_LIBS=NO" "-DBUILD_SHARED_LIBS=YES")
foreach (hsl IN ITEMS "" "-DHalide_SHARED_LIBS=NO" "-DHalide_SHARED_LIBS=YES")
foreach (comp IN ITEMS "" "-Djit_HALIDE_COMPONENTS=static" "-Djit_HALIDE_COMPONENTS=shared")
# Compute whether we expect to link to static or shared Halide given the relevant variables.
# Explicitly listing a component always wins. Then Halide_SHARED_LIBS takes over. If that's
# not available, it consults BUILD_SHARED_LIBS. If that's not defined, it defaults to shared,
# rather than static, because that's less likely to lead to pathologies with generators.
if (comp MATCHES "shared")
set(expect_shared TRUE)
elseif (comp MATCHES "static")
set(expect_shared FALSE)
elseif (hsl MATCHES "YES")
set(expect_shared TRUE)
elseif (hsl MATCHES "NO")
set(expect_shared FALSE)
elseif (bsl MATCHES "YES")
set(expect_shared TRUE)
elseif (bsl MATCHES "NO")
set(expect_shared FALSE)
else ()
set(expect_shared TRUE)
endif ()

set(test_name "${bsl} ${hsl} ${comp}")
string(REPLACE "-D" "" test_name "${test_name}")
string(STRIP "${test_name}" test_name)
string(MAKE_C_IDENTIFIER "jit_${test_name}" test_name)

set(build_step "check_builds_${test_name}")
set(check_link_step "check_linkage_${test_name}")

set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/jit/${test_name}")

# This builds and runs the tiny example app.
add_test(NAME "${build_step}"
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/jit" "${build_dir}"
--build-generator Ninja
--build-options ${bsl} ${hsl} ${comp} -DCMAKE_BUILD_TYPE=Release
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

# Run ldd on the output binary. The pass/fail regexes are set later.
add_test(NAME "${check_link_step}"
COMMAND ldd "${build_dir}/main")

# Make sure we don't run ldd before building...
set_tests_properties("${build_step}" PROPERTIES FIXTURES_SETUP "${test_name}")
set_tests_properties("${check_link_step}" PROPERTIES FIXTURES_REQUIRED "${test_name}")

if (expect_shared)
set_tests_properties("${check_link_step}" PROPERTIES PASS_REGULAR_EXPRESSION "libHalide")
else ()
set_tests_properties("${check_link_step}" PROPERTIES FAIL_REGULAR_EXPRESSION "libHalide")
endif ()
endforeach ()
endforeach ()
endforeach ()

##
# AOT integration tests
##

add_test(NAME aot_shared_generator
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/aot" "${CMAKE_CURRENT_BINARY_DIR}/aot-shared"
--build-generator Ninja
--build-options -DCMAKE_BUILD_TYPE=Release
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

add_test(NAME aot_static_generator
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/aot" "${CMAKE_CURRENT_BINARY_DIR}/aot-static"
--build-generator Ninja
--build-options -DHalide_SHARED_LIBS=NO -DCMAKE_BUILD_TYPE=Release
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

add_test(NAME aot_shared_generator_adams2019
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/aot" "${CMAKE_CURRENT_BINARY_DIR}/aot-shared-auto"
--build-generator Ninja
--build-options -DCMAKE_BUILD_TYPE=Release -Daot_USE_AUTOSCHEDULER=YES
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

add_test(NAME aot_static_generator_adams2019
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/aot" "${CMAKE_CURRENT_BINARY_DIR}/aot-static-auto"
--build-generator Ninja
--build-options -DHalide_SHARED_LIBS=NO -DCMAKE_BUILD_TYPE=Release -Daot_USE_AUTOSCHEDULER=YES
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

# Cannot use autoscheduler with generators linked to STATIC Halide
set_tests_properties(aot_static_generator_adams2019
PROPERTIES
WILL_FAIL TRUE
FAIL_REGULAR_EXPRESSION "Autoscheduler Halide::[A-Za-z0-9_]+ does not exist")

##
# Cross compiling test
##

if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
add_test(NAME cross_compile_host
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/xc" "${CMAKE_CURRENT_BINARY_DIR}/xc-host"
--build-generator Ninja
--build-options -DCMAKE_BUILD_TYPE=Release
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)

add_test(NAME cross_compile_aarch64
COMMAND
${CMAKE_CTEST_COMMAND}
--build-and-test "${CMAKE_CURRENT_LIST_DIR}/xc" "${CMAKE_CURRENT_BINARY_DIR}/xc-aarch64"
--build-generator Ninja
--build-options
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/../../cmake/toolchain.linux-aarch64.cmake
-DCMAKE_BUILD_TYPE=Release
--test-command ${CMAKE_CTEST_COMMAND} --output-on-failure)
endif ()
19 changes: 19 additions & 0 deletions test/integration/README.md
@@ -0,0 +1,19 @@
# Integration tests

These tests validate our CMake-built packages and make sure reasonable
interactions with the Halide-generated libraries and targets work. They run on
GitHub Actions, rather than the buildbots, to test building, installing, and
using Halide in **simple** cases from a clean build environment. In particular,
this folder **should not** be added to the main Halide build
via `add_subdirectory`.

The assumption is that we are building Halide with the latest CMake version, but
that our users might be on our oldest supported version. GitHub Actions makes it
easy to use two different versions on two different VMs.

There are scenarios here for JIT compilation, AOT compilation, and AOT _cross_
compilation from x86 to aarch64 (tested via Qemu). This test in particular cannot
be easily run on the buildbots because it requires two VMs: an Ubuntu build machine
for Halide, and an Ubuntu developer machine which installs the DEB packages.

Consult the `packaging.yml` workflow file for precise steps to run these locally.
26 changes: 26 additions & 0 deletions test/integration/aot/CMakeLists.txt
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.16)
project(aot)

enable_testing()

find_package(Halide REQUIRED)

option(aot_USE_AUTOSCHEDULER "Use the autoscheduler" OFF)
if (aot_USE_AUTOSCHEDULER)
set(extra_options AUTOSCHEDULER Halide::Adams2019)
endif ()

add_executable(add_gen add.cpp)
target_link_libraries(add_gen PRIVATE Halide::Generator)

add_halide_library(add FROM add_gen
${extra_options}
REGISTRATION add_registration)

add_executable(run_add ${add_registration})
target_link_libraries(run_add PRIVATE Halide::RunGenMain add)

add_test(NAME benchmark
COMMAND run_add --benchmarks=all --output_extents=[64,64])

set_tests_properties(benchmark PROPERTIES PASS_REGULAR_EXPRESSION "Best output throughput")
15 changes: 15 additions & 0 deletions test/integration/aot/add.cpp
@@ -0,0 +1,15 @@
#include <Halide.h>
using namespace Halide;

struct Add : Generator<Add> {
Output<Buffer<int32_t>> output{"output", 2};

void generate() {
Var x, y;
output(x, y) = x + y;

output.set_estimates({{0, 64}, {0, 64}});
}
};

HALIDE_REGISTER_GENERATOR(Add, add);
19 changes: 19 additions & 0 deletions test/integration/jit/CMakeLists.txt
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.16)
project(jit)

enable_testing()

set(jit_HALIDE_VERSION ""
CACHE STRING "Optional version argument to find_package(Halide)")

set(jit_HALIDE_COMPONENTS ""
CACHE STRING "Optional required-components argument to find_package(Halide)")

find_package(Halide ${jit_HALIDE_VERSION} REQUIRED ${jit_HALIDE_COMPONENTS})

add_executable(main main.cpp)
target_link_libraries(main PRIVATE Halide::Halide)

add_test(NAME validate COMMAND main)

set_tests_properties(validate PROPERTIES PASS_REGULAR_EXPRESSION "Success!")
24 changes: 24 additions & 0 deletions test/integration/jit/main.cpp
@@ -0,0 +1,24 @@
#include <Halide.h>
#include <cstdio>
#include <cstdlib>
using namespace Halide;

int main() {
Var x{"x"}, y{"y"};
Func test{"test"};

test(x, y) = x + y;
Buffer<int> output = test.realize({4, 4});

for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if (output(i, j) != (i + j)) {
fprintf(stderr, "output(%d, %d) = %d, expected %d", i, j, output(i, j), i + j);
return EXIT_FAILURE;
}
}
}

printf("Success!\n");
return EXIT_SUCCESS;
}
59 changes: 59 additions & 0 deletions test/integration/xc/CMakeLists.txt
@@ -0,0 +1,59 @@
cmake_minimum_required(VERSION 3.16)
project(xc LANGUAGES NONE)

enable_testing()

if (NOT CMAKE_CROSSCOMPILING)
# There is a bug with CTest's build-and-test that forwards environment
# variables, such as those set by the toolchain, to child processes. By
# not enabling CXX in the cross-compiling scenario, we can work around
# this bug. The alternative would be to not use build-and-test in the
# testing code, but it's used in every other location. This approach
# also has the benefit of being marginally faster because it doesn't
# waste a few seconds detecting a compiler that won't be used.
# https://gitlab.kitware.com/cmake/cmake/-/issues/22043
enable_language(CXX)

# Do things the easy way when not cross compiling
add_subdirectory(generators)
add_subdirectory(add)
else ()
# When cross compiling, use ExternalProject to stage building the
# generators with a host toolchain before passing the resulting
# package to the library build, which will use the target toolchain.
include(ExternalProject)

set(xc_HOST_TOOLCHAIN_FILE ""
CACHE FILEPATH "Toolchain file to use when compiling generators")

ExternalProject_Add(
generators
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generators"
INSTALL_COMMAND ""
BUILD_ALWAYS YES
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${xc_HOST_TOOLCHAIN_FILE}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
)

ExternalProject_Get_Property(generators BINARY_DIR)

ExternalProject_Add(
add
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/add"
INSTALL_COMMAND ""
BUILD_ALWAYS YES
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-Dxc-generators_ROOT=${BINARY_DIR}
)

ExternalProject_Add_StepDependencies(add configure generators)

ExternalProject_Get_Property(add BINARY_DIR)

add_test(NAME run-tests
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
WORKING_DIRECTORY ${BINARY_DIR})
endif ()

0 comments on commit ddc5893

Please sign in to comment.