ci: Enable parallel builds (#1241)

Our workflows and Dockerfiles now use Ninja on Linux & Mac, which
enables safe parallel builds. This significantly speeds up our
workflows.

GitHub Actions typical compilation times (build step only):
 - Linux 19m => 9m
 - macOS 23m => 8m
 - Windows 12m => 10m
 - Linux arm64 (self-hosted) 72m => 29m
 - Docker build 25m => 14m

Overall workflow time: 84m => 33m

Compilation time on my workstation (12 CPUs @3.3GHz): 15m => 3m

This also adds a new environment variable "PACKAGER_LOW_MEMORY_BUILD".
If defined when CMake is first run, this will configure the build to
disable parallel linking to reduce memory usage. This helps us avoid
failures on our self-hosted arm64 machines, where 6 CPUs share 4GB of
RAM.

NOTE: Parallel builds are **NOT** recommended with Unix Makefiles due to
the use of excessive RAM during parallel linking. Unix Makefiles, unlike
Ninja, cannot be configured to restrict parallel linking during a
parallel build. Anecdotally, parallel builds with Makefiles have
exhausted a system with 32GB RAM. (My workstation.)

In a follow-up, I will update the build documentation to refer to CMake
and recommend all of the flags now used in our workflows.
This commit is contained in:
Joey Parrish 2023-07-17 13:16:03 -07:00 committed by GitHub
parent 362d98ae62
commit 052fb64068
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 61 additions and 19 deletions

View File

@ -5,19 +5,22 @@
"os": "ubuntu-latest", "os": "ubuntu-latest",
"os_name": "linux", "os_name": "linux",
"target_arch": "x64", "target_arch": "x64",
"exe_ext": "" "exe_ext": "",
"generator": "Ninja"
}, },
{ {
"os": "macos-latest", "os": "macos-latest",
"os_name": "osx", "os_name": "osx",
"target_arch": "x64", "target_arch": "x64",
"exe_ext": "" "exe_ext": "",
"generator": "Ninja"
}, },
{ {
"os": "windows-latest", "os": "windows-latest",
"os_name": "win", "os_name": "win",
"target_arch": "x64", "target_arch": "x64",
"exe_ext": ".exe" "exe_ext": ".exe",
"generator": ""
} }
], ],
@ -27,7 +30,9 @@
"os": "self-hosted-linux-arm64", "os": "self-hosted-linux-arm64",
"os_name": "linux", "os_name": "linux",
"target_arch": "arm64", "target_arch": "arm64",
"exe_ext": "" "exe_ext": "",
"generator": "Ninja",
"low_mem": "yes"
} }
] ]
} }

View File

@ -100,12 +100,19 @@ jobs:
- name: Install Linux deps - name: Install Linux deps
if: runner.os == 'Linux' if: runner.os == 'Linux'
# NOTE: cmake is already installed in GitHub Actions VMs, but not # NOTE: CMake is already installed in GitHub Actions VMs, but not
# necessarily in a self-hosted runner. # necessarily in a self-hosted runner.
run: | run: |
sudo apt update && sudo apt install -y \ sudo apt update && sudo apt install -y \
cmake \ cmake \
libc-ares-dev libc-ares-dev \
ninja-build
- name: Install Mac deps
if: runner.os == 'macOS'
# NOTE: GitHub Action VMs do not install ninja by default.
run: |
brew install ninja
- name: Generate build files - name: Generate build files
run: | run: |
@ -117,6 +124,18 @@ jobs:
LIBPACKAGER_SHARED="OFF" LIBPACKAGER_SHARED="OFF"
fi fi
# If set, override the default generator for the platform.
# Not every entry in the build matrix config defines this.
# If this is blank, CMake will choose the default generator.
export CMAKE_GENERATOR="${{ matrix.generator }}"
# If set, configure the build to restrict parallel operations.
# This helps us avoid the compiler failing due to a lack of RAM
# on our arm64 build devices (4GB RAM shared among 6 CPUs).
if [[ "${{ matrix.low_mem }}" != "" ]]; then
export PACKAGER_LOW_MEMORY_BUILD=yes
fi
cmake \ cmake \
-DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" \ -DCMAKE_BUILD_TYPE="${{ matrix.build_type }}" \
-DLIBPACKAGER_SHARED="$LIBPACKAGER_SHARED" \ -DLIBPACKAGER_SHARED="$LIBPACKAGER_SHARED" \
@ -128,7 +147,7 @@ jobs:
# Visual Studio on Windows. Note that the VS generator is what cmake # Visual Studio on Windows. Note that the VS generator is what cmake
# calls a "multi-configuration" generator, and so the desired build # calls a "multi-configuration" generator, and so the desired build
# type must be specified for Windows. # type must be specified for Windows.
run: cmake --build build/ --config "${{ matrix.build_type }}" run: cmake --build build/ --config "${{ matrix.build_type }}" --parallel
- name: Test - name: Test
run: ctest -C "${{ matrix.build_type }}" -V --test-dir build/ run: ctest -C "${{ matrix.build_type }}" -V --test-dir build/

View File

@ -4,15 +4,15 @@ FROM alpine:3.12 as builder
RUN apk add --no-cache \ RUN apk add --no-cache \
bash curl \ bash curl \
bsd-compat-headers c-ares-dev linux-headers \ bsd-compat-headers c-ares-dev linux-headers \
build-base cmake git python3 build-base cmake git ninja python3
# Build shaka-packager from the current directory, rather than what has been # Build shaka-packager from the current directory, rather than what has been
# merged. # merged.
WORKDIR shaka-packager WORKDIR shaka-packager
COPY . /shaka-packager/ COPY . /shaka-packager/
RUN mkdir build RUN mkdir build
RUN cmake -S . -B build RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -G Ninja
RUN make -C build RUN cmake --build build/ --config Debug --parallel
# Copy only result binaries to our final image. # Copy only result binaries to our final image.
FROM alpine:3.12 FROM alpine:3.12

View File

@ -29,3 +29,15 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
message(FATAL_ERROR "GCC version must be at least 9! (Found ${CMAKE_CXX_COMPILER_VERSION})") message(FATAL_ERROR "GCC version must be at least 9! (Found ${CMAKE_CXX_COMPILER_VERSION})")
endif() endif()
endif() endif()
# If the environment variable PACKAGER_LOW_MEMORY_BUILD is defined, limit the
# number of parallel processes. This is used in our workflow to keep our arm64
# builds from failing. There, we only have 4GB RAM to share among 6 CPUs.
# NOTE: This only affects CMake's Ninja generator.
if(DEFINED ENV{PACKAGER_LOW_MEMORY_BUILD})
set_property(GLOBAL PROPERTY JOB_POOLS
compile_jobs=4
link_jobs=1)
set(CMAKE_JOB_POOL_COMPILE compile_jobs)
set(CMAKE_JOB_POOL_LINK link_jobs)
endif()

View File

@ -4,7 +4,7 @@ FROM alpine:3.12
RUN apk add --no-cache \ RUN apk add --no-cache \
bash curl \ bash curl \
bsd-compat-headers c-ares-dev linux-headers \ bsd-compat-headers c-ares-dev linux-headers \
build-base cmake git python3 build-base cmake git ninja python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -4,7 +4,7 @@ FROM archlinux:latest
RUN pacman -Sy --needed --noconfirm \ RUN pacman -Sy --needed --noconfirm \
core/which \ core/which \
c-ares \ c-ares \
cmake gcc git make python3 cmake gcc git ninja python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -1,10 +1,16 @@
FROM tgagor/centos:stream9 FROM tgagor/centos:stream9
# For CentOS, Ninja is only available from the "CRB" ("Code Ready Builder")
# repo. Enable that first.
RUN dnf update
RUN dnf install -y yum-utils
RUN dnf config-manager --set-enabled crb
# Install utilities, libraries, and dev tools. # Install utilities, libraries, and dev tools.
RUN yum install -y \ RUN yum install -y \
which \ which \
c-ares-devel libatomic \ c-ares-devel libatomic \
cmake gcc-c++ git python3 cmake gcc-c++ git ninja-build python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y apt-utils
RUN apt-get install -y \ RUN apt-get install -y \
curl \ curl \
libc-ares-dev \ libc-ares-dev \
build-essential cmake git python3 build-essential cmake git ninja-build python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -4,7 +4,7 @@ FROM fedora:34
RUN yum install -y \ RUN yum install -y \
which \ which \
c-ares-devel libatomic \ c-ares-devel libatomic \
cmake gcc-c++ git python3 cmake gcc-c++ git ninja-build python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -4,7 +4,7 @@ FROM opensuse/leap:15.5
RUN zypper in -y \ RUN zypper in -y \
curl which \ curl which \
c-ares-devel \ c-ares-devel \
cmake gcc9-c++ git python3 cmake gcc9-c++ git ninja python3
# OpenSuse 15 doesn't have the required gcc 9+ by default, but we can install # OpenSuse 15 doesn't have the required gcc 9+ by default, but we can install
# it as gcc9 and symlink it. # it as gcc9 and symlink it.

View File

@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y apt-utils
RUN apt-get install -y \ RUN apt-get install -y \
curl \ curl \
libc-ares-dev \ libc-ares-dev \
build-essential cmake git python3 build-essential cmake git ninja-build python3
# Build and run this docker by mapping shaka-packager with # Build and run this docker by mapping shaka-packager with
# -v "shaka-packager:/shaka-packager". # -v "shaka-packager:/shaka-packager".

View File

@ -85,8 +85,8 @@ for DOCKER_FILE in ${SCRIPT_DIR}/dockers/*; do
RAN_SOMETHING=1 RAN_SOMETHING=1
docker build --pull -t ${CONTAINER} -f ${DOCKER_FILE} ${SCRIPT_DIR}/dockers/ docker build --pull -t ${CONTAINER} -f ${DOCKER_FILE} ${SCRIPT_DIR}/dockers/
mkdir -p "${TEMP_BUILD_DIR}" mkdir -p "${TEMP_BUILD_DIR}"
docker_run cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Debug docker_run cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Debug -G Ninja
docker_run cmake --build build/ --config Debug docker_run cmake --build build/ --config Debug --parallel
docker_run bash -c "cd build && ctest -C Debug -V" docker_run bash -c "cd build && ctest -C Debug -V"
rm -rf "${TEMP_BUILD_DIR}" rm -rf "${TEMP_BUILD_DIR}"
done done