| #!/bin/bash |
| ############################################################################### |
| # This script tests the flow to build libtorch locally with optimized binary |
| # size for mobile devices and the flow to integrate it with a simple predictor |
| # in c++. |
| # |
| # Supported custom build types: |
| # |
| # 1. `TEST_DEFAULT_BUILD=1 ./build.sh` - it is similar to the prebuilt libtorch |
| # libraries released for Android and iOS (same CMake build options + host |
| # toolchain), which doesn't contain autograd function nor backward ops thus is |
| # smaller than full LibTorch. |
| # |
| # 2. `TEST_CUSTOM_BUILD_STATIC=1 ./build.sh` - optimizes libtorch size by only |
| # including ops used by a specific model. It relies on the static dispatch + |
| # linker to prune code. |
| # |
| ############################################################################### |
| |
| set -ex -o pipefail |
| |
| SRC_ROOT="$( cd "$(dirname "$0")"/../../.. ; pwd -P)" |
| TEST_SRC_ROOT="${SRC_ROOT}/test/mobile/custom_build" |
| BUILD_ROOT="${BUILD_ROOT:-${SRC_ROOT}/build_test_custom_build}" |
| mkdir -p "${BUILD_ROOT}" |
| cd "${BUILD_ROOT}" |
| |
| prepare_model_and_dump_root_ops() { |
| cd "${BUILD_ROOT}" |
| MODEL="${BUILD_ROOT}/MobileNetV2.pt" |
| ROOT_OPS="${BUILD_ROOT}/MobileNetV2.yaml" |
| |
| python "${TEST_SRC_ROOT}/prepare_model.py" |
| } |
| |
| run_default_build() { |
| LIBTORCH_BUILD_ROOT="${BUILD_ROOT}/build_default_libtorch" |
| LIBTORCH_INSTALL_PREFIX="${LIBTORCH_BUILD_ROOT}/install" |
| |
| BUILD_ROOT="${LIBTORCH_BUILD_ROOT}" \ |
| "${SRC_ROOT}/scripts/build_mobile.sh" |
| } |
| |
| run_custom_build_with_static_dispatch() { |
| LIBTORCH_BUILD_ROOT="${BUILD_ROOT}/build_custom_libtorch_static" |
| LIBTORCH_INSTALL_PREFIX="${LIBTORCH_BUILD_ROOT}/install" |
| |
| # Here it generates registration code for used ROOT ops only, whose unboxing |
| # kernels are still needed by the JIT runtime. The intermediate ops will be |
| # automatically kepted by the linker as they are statically referenced by the |
| # static dispatch code, for which we can bypass the registration. |
| # We don't set '-DSTATIC_DISPATCH_BACKEND=CPU' explicitly to test automatic |
| # fallback to static dispatch. |
| BUILD_ROOT="${LIBTORCH_BUILD_ROOT}" \ |
| "${SRC_ROOT}/scripts/build_mobile.sh" \ |
| -DCMAKE_CXX_FLAGS="-DSTRIP_ERROR_MESSAGES" \ |
| -DSELECTED_OP_LIST="${ROOT_OPS}" |
| } |
| |
| build_predictor() { |
| PREDICTOR_BUILD_ROOT="${BUILD_ROOT}/predictor" |
| |
| rm -rf "${PREDICTOR_BUILD_ROOT}" && mkdir -p "${PREDICTOR_BUILD_ROOT}" |
| cd "${PREDICTOR_BUILD_ROOT}" |
| |
| cmake "${TEST_SRC_ROOT}" \ |
| -DCMAKE_PREFIX_PATH="${LIBTORCH_INSTALL_PREFIX}" \ |
| -DCMAKE_BUILD_TYPE=Release |
| |
| make |
| } |
| |
| run_predictor() { |
| cd "${PREDICTOR_BUILD_ROOT}" |
| ./Predictor "${MODEL}" > output.txt |
| |
| if cmp -s output.txt "${TEST_SRC_ROOT}/expected_output.txt"; then |
| echo "Test result is the same as expected." |
| else |
| echo "Test result is DIFFERENT from expected!" |
| diff output.txt "${TEST_SRC_ROOT}/expected_output.txt" |
| exit 1 |
| fi |
| } |
| |
| test_default_build() { |
| prepare_model_and_dump_root_ops |
| run_default_build |
| build_predictor |
| run_predictor |
| } |
| |
| test_custom_build_with_static_dispatch() { |
| prepare_model_and_dump_root_ops |
| run_custom_build_with_static_dispatch |
| build_predictor |
| run_predictor |
| } |
| |
| if [ -n "${TEST_DEFAULT_BUILD}" ]; then |
| test_default_build |
| fi |
| |
| if [ -n "${TEST_CUSTOM_BUILD_STATIC}" ]; then |
| test_custom_build_with_static_dispatch |
| fi |