Skip to content

Commit

Permalink
Use explicit host build strategy for cross compiling HANNK (#6365)
Browse files Browse the repository at this point in the history
* Ignore local emsdk clone

* Fix usage of CMAKE_BUILD_TYPE

* Only print the Halide target info once per CMake run

* Fix Halide "cmake" target detection for Emscripten

* Prefer target_link_options to _link_libraries when applicable

* Validate, rather than find, NODE_JS_EXECUTABLE (set by emsdk)

* Emscripten already wraps tests with node.

* Add dependency on Android logging library.

* For cross-compiling, find host tools instead of recursive call.

Rather than shelling out via execute_process and potentially
guessing the toolchain options wrong, expect to find our host
tools (i.e. generators) in a package called "hannk_tools".

The package is created by the host build via the CMake export()
command. Importing this package in the cross build creates
IMPORTED targets with the same names as our generators. We then
use these generators rather than creating generators for the
target build.

* Rework cross-compiling script.

* Respond to (easy) reviewer comments.

* Add HANNK_AOT_HOST_ONLY option. Use in script.

* [hannk] tests should only process .tflite files (#6368)

currently, random dotfiles (e.g. .DS_Store on OSX) can creep in, causing bogus failures

* Add comment about node wrapping.

* Rename hannk_tools to hannk-halide_generators

* Add comment about exporting targets.

* Bump version to Halide 14.0.0 (#6369)

Co-authored-by: Steven Johnson <srj@google.com>
  • Loading branch information
alexreinking and steven-johnson committed Nov 1, 2021
1 parent 0829d1d commit dae7c4e
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 188 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16...3.20)
project(Halide
VERSION 13.0.0
VERSION 14.0.0
DESCRIPTION "Halide compiler and libraries"
HOMEPAGE_URL "https://halide-lang.org")

Expand Down
1 change: 1 addition & 0 deletions apps/hannk/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
build*/
bin/
emsdk
85 changes: 40 additions & 45 deletions apps/hannk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)

enable_testing()

# ----------------------------

option(HANNK_AOT_HOST_ONLY "Only build AOT host tools for cross-compiling" OFF)

option(HANNK_BUILD_TFLITE "Build TFLite+Delegate for HANNK" ON)
if (HANNK_BUILD_TFLITE AND (Halide_TARGET MATCHES "wasm"))
message(FATAL_ERROR "HANNK_BUILD_TFLITE must be OFF when targeting wasm")
endif()
endif ()
message(STATUS "HANNK_BUILD_TFLITE is ${HANNK_BUILD_TFLITE}")

# -fPIC is necessary for .so builds (at least on Linux); not necessary for the non-delegate
Expand All @@ -21,35 +25,43 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)

# Find HalideHelpers -- this is just the Runtime headers, but no libraries
find_package(HalideHelpers REQUIRED)

# Set up the version of TFLite we expect
# (We need to do this even if HANNK_BUILD_TFLITE is off,
# so that the .tflite file parser can get the right schema)
set(TFLITE_VERSION_MAJOR "2" CACHE STRING "Major version of TFLite to assume")
set(TFLITE_VERSION_MINOR "6" CACHE STRING "Minor version of TFLite to assume")
set(TFLITE_VERSION_PATCH "0" CACHE STRING "Patch version of TFLite to assume")
set(TFLITE_VERSION "${TFLITE_VERSION_MAJOR}.${TFLITE_VERSION_MINOR}.${TFLITE_VERSION_PATCH}")

# ----------------------------

add_compile_definitions(TFLITE_VERSION_MAJOR=${TFLITE_VERSION_MAJOR})
add_compile_definitions(TFLITE_VERSION_MINOR=${TFLITE_VERSION_MINOR})
add_compile_definitions(TFLITE_VERSION_PATCH=${TFLITE_VERSION_PATCH})
if (HANNK_BUILD_TFLITE)
add_compile_definitions(HANNK_BUILD_TFLITE=1)
else ()
add_compile_definitions(HANNK_BUILD_TFLITE=0)
endif ()
add_compile_definitions(HANNK_BUILD_TFLITE=$<BOOL:${HANNK_BUILD_TFLITE}>)

set(TFLITE_VERSION "${TFLITE_VERSION_MAJOR}.${TFLITE_VERSION_MINOR}.${TFLITE_VERSION_PATCH}")
# ----------------------------

# Find HalideHelpers -- this is just the Runtime headers and CMake functions, but no libraries
find_package(HalideHelpers REQUIRED)

# ----------------------------

add_subdirectory(halide)
if (HANNK_AOT_HOST_ONLY)
# Don't add anything else to the build... everything for AOT is in the halide subdirectory
return()
endif ()

add_subdirectory(interpreter)
add_subdirectory(tflite)
add_subdirectory(util)
if (HANNK_BUILD_TFLITE)
add_subdirectory(delegate)
endif ()

# ----------------------------

# Benchmarking executable
add_executable(benchmark benchmark.cpp)
target_link_libraries(benchmark PRIVATE
Expand All @@ -72,28 +84,18 @@ target_include_directories(compare_vs_tflite
# TODO: Surely there's a better way to set Emscripten flags.
if (Halide_TARGET MATCHES "wasm")
foreach (t IN ITEMS benchmark compare_vs_tflite)
target_link_libraries(${t} PRIVATE
"-s ALLOW_MEMORY_GROWTH=1"
"-s ENVIRONMENT=node"
"-s NODERAWFS"
# Note: "SHELL:" prevents de-duplication of the -s flag.
target_link_options(
${t} PRIVATE
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
"SHELL:-s ENVIRONMENT=node"
"SHELL:-s NODERAWFS"
"SHELL:$<$<CONFIG:Debug>:-s ASSERTIONS=1>"
)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_libraries(${t} PRIVATE
"-s ASSERTIONS=1"
)
endif()
endforeach()
endif()

# TODO: Replicated from Halide's wasm dependency code; we should move this
# into a Helper file included in the install, perhaps?
function(_find_node_js)
find_program(NODE_JS_EXECUTABLE node nodejs)

if (NOT NODE_JS_EXECUTABLE)
message(FATAL_ERROR "Could not find nodejs. Please set NODE_JS_EXECUTABLE on the CMake command line.")
endif ()
endforeach ()
endif ()

if (Halide_TARGET MATCHES "wasm" AND NODE_JS_EXECUTABLE)
execute_process(COMMAND "${NODE_JS_EXECUTABLE}" --version
OUTPUT_VARIABLE NODE_JS_VERSION_RAW
OUTPUT_STRIP_TRAILING_WHITESPACE)
Expand All @@ -102,25 +104,18 @@ function(_find_node_js)
if (NODE_JS_VERSION VERSION_LESS "16.13")
message(FATAL_ERROR "Halide requires Node v16.13 or later, but found ${NODE_JS_VERSION_RAW} at ${NODE_JS_EXECUTABLE}. Please set NODE_JS_EXECUTABLE on the CMake command line.")
endif ()
endfunction()

endif ()

# Tests
file(GLOB TEST_FILES CONFIGURE_DEPENDS "test/*/*")
file(GLOB TEST_FILES CONFIGURE_DEPENDS "test/*/*.tflite")
foreach (t IN LISTS TEST_FILES)
file(RELATIVE_PATH test_name ${hannk_SOURCE_DIR} ${t})

set(LAUNCHER "")
if (Halide_TARGET MATCHES "wasm")
_find_node_js()
add_test(NAME ${test_name}
COMMAND ${NODE_JS_EXECUTABLE} compare_vs_tflite.js ${t} --benchmark 0)
else()
add_test(NAME ${test_name}
COMMAND compare_vs_tflite ${t} --benchmark 0)
endif()
# Emscripten sets CMAKE_CROSSCOMPILING_TOOLCHAIN to NODE_JS_EXECUTABLE,
# which ensures these tests will run in Node.
add_test(NAME ${test_name}
COMMAND compare_vs_tflite ${t} --benchmark 0)

set_tests_properties(${test_name} PROPERTIES
LABELS hannk_tests)
endforeach()


endforeach ()
6 changes: 3 additions & 3 deletions apps/hannk/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ build: \
$(BIN)/$(HL_TARGET)/compare_vs_tflite

test: compare_vs_tflite
$(foreach test_model, $(shell ls -1 test/*/*), $(BIN)/$(HL_TARGET)/compare_vs_tflite $(test_model) --benchmark 0;)
$(foreach test_model, $(shell ls -1 test/*/*.tflite), $(BIN)/$(HL_TARGET)/compare_vs_tflite $(test_model) --benchmark 0;)

test-hexagon-sim: $(BIN)/$(HL_TARGET)/$(BENCHMARK_OUT)
@mkdir -p $@
echo "Benchmarking tests..."
$(foreach test_model, $(shell ls -1 test/*/*), BIN=$(BIN) ./run_benchmark_on_hexagon_sim.sh $(test_model);)
$(foreach test_model, $(shell ls -1 test/*/*.tflite), BIN=$(BIN) ./run_benchmark_on_hexagon_sim.sh $(test_model);)

test-hexagon-device: $(BIN)/$(HL_TARGET)/$(BENCHMARK_OUT)
echo "Benchmarking tests..."
Expand All @@ -51,7 +51,7 @@ test-hexagon-device: $(BIN)/$(HL_TARGET)/$(BENCHMARK_OUT)
adb push test/. /vendor/bin/hannk-test
adb push $(HEXAGON_SDK_ROOT)/libs/run_main_on_hexagon/ship/android_aarch64/run_main_on_hexagon /vendor/bin/run_main_on_hexagon
adb push $(HEXAGON_SDK_ROOT)/libs/run_main_on_hexagon/ship/hexagon_toolv84_v65/librun_main_on_hexagon_skel.so /vendor/lib/rfsa/adsp/
$(foreach test_model, $(shell ls -1 test/*/*), adb shell 'cd /vendor/bin; touch /vendor/lib/rfsa/adsp/run_main_on_hexagon.farf; ./run_main_on_hexagon 3 /vendor/bin/$(BENCHMARK_OUT) --verbose hannk-$(test_model)';)
$(foreach test_model, $(shell ls -1 test/*/*.tflite), adb shell 'cd /vendor/bin; touch /vendor/lib/rfsa/adsp/run_main_on_hexagon.farf; ./run_main_on_hexagon 3 /vendor/bin/$(BENCHMARK_OUT) --verbose hannk-$(test_model)';)

clean:
rm -rf $(BIN)
Expand Down
125 changes: 80 additions & 45 deletions apps/hannk/configure_cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,114 @@

set -e

HANNK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
HANNK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"

if [ -z ${BUILD_DIR} ]; then
BUILD_DIR="${HANNK_DIR}/build"
if [ -z "${BUILD_DIR}" ]; then
BUILD_DIR="${HANNK_DIR}/build"
fi

if [ -z ${HALIDE_INSTALL_PATH} ]; then
HALIDE_INSTALL_PATH=${HOME}/halide-14-install/
if [ -z "${HALIDE_INSTALL_PATH}" ]; then
HALIDE_INSTALL_PATH="${HOME}/halide-14-install/"
fi

if [ -z ${HL_TARGET} ]; then
HL_TARGET=host
if [ -z "${HL_TARGET}" ]; then
HL_TARGET=host
fi

if [ -z "${CMAKE_GENERATOR}" ]; then
CMAKE_GENERATOR=Ninja
CMAKE_GENERATOR=Ninja
fi

if [ -z "${CMAKE_BUILD_TYPE}" ]; then
CMAKE_BUILD_TYPE=Release
CMAKE_BUILD_TYPE=Release
fi

if [ -z "${ANDROID_PLATFORM}" ]; then
ANDROID_PLATFORM=21
fi

if [ -z "${HANNK_BUILD_TFLITE}" ]; then
HANNK_BUILD_TFLITE=ON
HANNK_BUILD_TFLITE=ON
else
HANNK_BUILD_TFLITE=OFF
HANNK_BUILD_TFLITE=OFF
fi

PREFIX=
EXTRAS=
## In a cross-compiling scenario, use a separate host and build dir
# TODO: figure out if there's a way to generalize "is this crosscompiling or not", and just make this a single if-else

if [[ "${HL_TARGET}" =~ ^arm-64-android.* ]]; then

# TODO: this doesn't work (yet); crosscompiling in CMake is painful.
echo Configuring for Android arm64-v8a build...
echo Using ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}
echo Using CMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake

EXTRAS="-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DANDROID_ABI=arm64-v8a"

HOST_BUILD_DIR="${BUILD_DIR}/_host"
HOST_BUILD_TARGET=(--target hannk-halide_generators)
HOST_HL_TARGET=host
HOST_CMAKE_DEFS=(-DHANNK_AOT_HOST_ONLY=ON)
elif [[ "${HL_TARGET}" =~ ^wasm-32-wasmrt.* ]]; then

PREFIX=emcmake
HANNK_BUILD_TFLITE=OFF

HOST_BUILD_DIR="${BUILD_DIR}/_host"
HOST_BUILD_TARGET=(--target hannk-halide_generators)
HOST_HL_TARGET=host
HOST_CMAKE_DEFS=(-DHANNK_AOT_HOST_ONLY=ON)
else
HOST_BUILD_DIR="${BUILD_DIR}"
HOST_BUILD_TARGET=()
HOST_HL_TARGET="${HL_TARGET}"
HOST_CMAKE_DEFS=()
fi

echo Assuming host build...
## Build HANNK for the host no matter what

fi
echo "Configuring HANNK for ${HOST_HL_TARGET}"
cmake \
-G "${CMAKE_GENERATOR}" \
-S "${HANNK_DIR}" \
-B "${HOST_BUILD_DIR}" \
"${HOST_CMAKE_DEFS[@]}" \
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \
-DHalide_DIR="${HALIDE_INSTALL_PATH}/lib/cmake/Halide" \
-DHalideHelpers_DIR="${HALIDE_INSTALL_PATH}/lib/cmake/HalideHelpers" \
-DHalide_TARGET="${HOST_HL_TARGET}" \
-DHANNK_BUILD_TFLITE=${HANNK_BUILD_TFLITE}

if [ -n "${NODE_JS_EXECUTABLE}" ]; then
EXTRAS="${EXTRAS} -DNODE_JS_EXECUTABLE=${NODE_JS_EXECUTABLE}"
echo Using NODE_JS_EXECUTABLE=${NODE_JS_EXECUTABLE}
if [ -z "${HOST_BUILD_TARGET[*]}" ]; then
echo "Building HANNK for ${HOST_HL_TARGET}"
else
echo "Building HANNK host generator executables"
fi
cmake --build "${HOST_BUILD_DIR}" "${HOST_BUILD_TARGET[@]}"

echo Using HalideInstall=${HALIDE_INSTALL_PATH}
echo Using BUILD_DIR=${BUILD_DIR}
echo Using build tool=${CMAKE_GENERATOR}
echo Using CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
echo Using HL_TARGET=${HL_TARGET}
echo Using HANNK_BUILD_TFLITE=${HANNK_BUILD_TFLITE}
## Now if we're cross-compiling for Android or WASM, set up the build
## for that, using the platform-provided CMake toolchain files.

mkdir -p "${BUILD_DIR}"
cd "${BUILD_DIR}"
if [[ "${HL_TARGET}" =~ ^arm-64-android.* ]]; then
echo "Using ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}"
echo "Using CMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake"
CROSS_CMAKE_DEFS=(
-DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake"
-DANDROID_ABI=arm64-v8a
"-DANDROID_PLATFORM=${ANDROID_PLATFORM}"
# Required because TFLite's internal Eigen tries to compile an unnecessary BLAS with the system Fortran compiler.
"-DCMAKE_Fortran_COMPILER=NO"
)
elif [[ "${HL_TARGET}" =~ ^wasm-32-wasmrt.* ]]; then
echo "Using NODE_JS_EXECUTABLE=${NODE_JS_EXECUTABLE}"
CROSS_CMAKE_DEFS=(
-DCMAKE_TOOLCHAIN_FILE="${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
-DNODE_JS_EXECUTABLE="${NODE_JS_EXECUTABLE}"
)
else
# Not cross-compiling, so we're done.
exit
fi

${PREFIX} cmake \
${EXTRAS} \
echo "Configuring cross-build HANNK for ${HL_TARGET}"
cmake \
-G "${CMAKE_GENERATOR}" \
-S "${HANNK_DIR}" \
-B "${BUILD_DIR}" \
"${CROSS_CMAKE_DEFS[@]}" \
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \
-DHalide_DIR="${HALIDE_INSTALL_PATH}/lib/cmake/Halide" \
-DHANNK_BUILD_TFLITE=OFF \
-DHalide_TARGET="${HL_TARGET}" \
-DHalideHelpers_DIR="${HALIDE_INSTALL_PATH}/lib/cmake/HalideHelpers" \
-DHalide_TARGET=${HL_TARGET} \
-DHANNK_BUILD_TFLITE=${HANNK_BUILD_TFLITE} \
-S "${HANNK_DIR}" \
-B "${BUILD_DIR}"
-Dhannk-halide_generators_ROOT="${HOST_BUILD_DIR}"

echo "Building cross-build HANNK for ${HL_TARGET}"
cmake --build "${BUILD_DIR}"
Loading

0 comments on commit dae7c4e

Please sign in to comment.