-
Notifications
You must be signed in to change notification settings - Fork 18
290 lines (284 loc) · 14 KB
/
celerity_ci.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
name: Celerity CI
on:
push:
# We perform CI on "push" only on master, otherwise it is redundant with the "pull_request" trigger
branches:
- master
pull_request:
workflow_dispatch:
inputs:
test-head:
description: "Test against 'HEAD' revisions"
type: boolean
required: true
default: false
tag-latest:
description: "Tag 'HEAD' revisions as 'latest' if successful"
type: boolean
required: true
default: false
# We use nightly builds to determine whether CI passes for "HEAD" revisions
# of DPC++ and AdaptiveCpp. If so, these revisions are tagged as "latest" and
# used for all subsequent CI runs.
schedule:
# Every night at 05:00 UTC
- cron: "0 5 * * *"
jobs:
# Run Clang-Tidy checks
#
# Note: This action currently only supports pull_request triggers (as it creates review comments)
#
# TODO: This should be combined with the report (or "lint") step, really
clang-tidy:
if: github.event.pull_request
runs-on: [ self-hosted, slurm-intel ]
env:
container-workspace: <placeholder>
build-dir: /root/build
container:
image: ghcr.io/celerity/celerity-lint
volumes:
- ccache:/ccache
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
# Here and in jobs below: We need to manually set the container workspace
# path as an environment variable, as (curiously) the `github.workspace` context
# variable contains the path on the container host (but $GITHUB_WORKSPACE is correct).
- name: Set container workspace environment variable
run: echo "container-workspace=$GITHUB_WORKSPACE" > $GITHUB_ENV
- uses: actions/checkout@v4
with:
submodules: true
- name: Fetch base branch
run: git fetch --no-tags --no-recurse-submodules origin "${{ github.event.pull_request.base.ref }}"
# We only want to configure CMake, so we build the "help" target,
# which doesn't actually do anything (other than print all targets).
- name: Configure CMake
run: bash -o pipefail -c "bash /root/build-celerity.sh ${{ env.container-workspace }} --build-type Debug --target help"
- name: Run clang-tidy
continue-on-error: true # clang-tidy-diff.py returns 1 if there are any errors; continue in that case (if something actually went wrong, there won't be a fixes file)
# -j48 for gpuc5
run: git diff -U0 origin/${{ github.event.pull_request.base.ref }} | clang-tidy-diff.py -j48 -p1 -path ${{ env.build-dir }} -export-fixes clang-tidy-fixes.yml
shell: bash # enables -o pipefail
- name: Create clang-tidy report comments
uses: platisd/clang-tidy-pr-comments@v1
with:
python_path: python3 # Use our own Python installation
github_token: ${{ secrets.GITHUB_TOKEN }}
clang_tidy_fixes: "${{ env.container-workspace }}/clang-tidy-fixes.yml"
repo_path_prefix: "/__w"
# We need to jump through some hoops to have different build matrices based on what triggered the workflow.
# For normal CI runs we want to build and test against everything except the "HEAD" revisions, whereas during
# nightly builds we *only* want those.
#
# Current workaround is to represent the matrix as a JSON object, which is then deserialized in the next job.
read-build-matrix:
runs-on: self-hosted
outputs:
matrix: ${{ steps.read-json-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: read-json-matrix
name: Read build matrix from file
shell: python
run: |
import json
import os
with open("${{ github.workspace }}/.github/workflows/build_matrix.json") as f:
matrices = json.load(f)
if '${{ github.event_name != 'schedule' && inputs.test-head == false }}' == 'true':
matrix = matrices['default']
else:
matrix = matrices['nightly']
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
print('matrix={ "include":%s }' % json.dumps(matrix), file=fh)
build-and-test:
needs: read-build-matrix
runs-on: [ self-hosted, "slurm-${{ matrix.platform }}" ]
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.read-build-matrix.outputs.matrix) }}
# These outputs are required by the image tagging step, only set during nightly builds.
outputs:
dpcpp-HEAD-Debug-works: ${{ steps.set-head-results.outputs.dpcpp-HEAD-Debug-works }}
dpcpp-HEAD-Release-works: ${{ steps.set-head-results.outputs.dpcpp-HEAD-Release-works }}
dpcpp-HEAD-ubuntu-version: ${{ steps.set-head-results.outputs.dpcpp-HEAD-ubuntu-version }}
acpp-HEAD-Debug-works: ${{ steps.set-head-results.outputs.acpp-HEAD-Debug-works }}
acpp-HEAD-Release-works: ${{ steps.set-head-results.outputs.acpp-HEAD-Release-works }}
acpp-HEAD-ubuntu-version: ${{ steps.set-head-results.outputs.acpp-HEAD-ubuntu-version }}
env:
build-name: ${{ matrix.platform }}-ubuntu${{ matrix.ubuntu-version }}-${{ matrix.sycl }}-${{ matrix.sycl-version }}-${{ matrix.build-type }}
container-workspace: <placeholder>
build-dir: /root/build
examples-build-dir: /root/build-examples
container:
image: ghcr.io/celerity/celerity-build/${{ matrix.sycl }}:ubuntu${{ matrix.ubuntu-version }}-${{ matrix.sycl-version }}
volumes:
- ccache:/ccache
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
# We limit DPC++ to Level-Zero devices (instead of e.g. also showing OpenCL or CUDA devices).
# Most importantly, despite its naming, this currently also avoids the "Unified Runtime over Level-Zero", which
# doesn't seem to be quite ready for production use yet (= it crashes).
- name: Set environment variables
run: |
echo "container-workspace=$GITHUB_WORKSPACE" > $GITHUB_ENV
echo "ONEAPI_DEVICE_SELECTOR=level_zero:*" >> $GITHUB_ENV
echo "SIMSYCL_SYSTEM=$GITHUB_WORKSPACE/ci/simsycl-system.json" >> $GITHUB_ENV
- name: Print exact SYCL revision used for this CI run
run: cat /VERSION
- uses: actions/checkout@v4
with:
submodules: true
# In SimSYCL images, /root/celerity-options.sh automatically enables coverage for Debug builds, and Tracy support for Release builds
- name: Build and install Celerity
run: bash -o pipefail -c "bash /root/build-celerity.sh ${{ env.container-workspace }} --build-type ${{ matrix.build-type }} --mpi ${{ matrix.mpi }} --target install 2>&1 | tee ${{ env.build-name }}.log"
# Upload build log for report step
- name: Upload build logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.build-name }}
path: ${{ env.build-name }}.log
- name: Build examples against installed Celerity
run: bash /root/build-examples.sh ${{ env.container-workspace }}/examples --build-type ${{ matrix.build-type }}
- name: Reset coverage counters
if: matrix.build-type == 'Debug' && matrix.sycl == 'simsycl' # celerity-build/simsycl image enables --coverage for Debug builds
run: fastcov -z -d "${{ env.build-dir }}"
# For a run with ASan, we need to fake dlclose() so all shared libraries are still mapped when leaks are evaluated
# - otherwise, we will see "<unknown module>" instead of a proper trace if it originated in an unloaded library
# (see https://github.com/google/sanitizers/issues/89#issuecomment-406316683). LD_PRELOAD will be set to CI_LD_PRELOAD
# by /root/capture-backtrace.sh (otherwise we would also preload for other processes like bash, which we don't want to do).
# Also, hwloc (used by OpenMPI) will attempt to dlopen(RTLD_DEEPBIND) for GPU backend discovery which is incompatible
# with sanitizers but also irrelevant for a SimSYCL build, so we set HWLOC_COMPONENTS accordingly.
- name: Prepare Sanitizer run
if: matrix.sycl == 'simsycl' && matrix.build-type == 'Debug'
run: |
echo "ASAN_OPTIONS=detect_leaks=1" >> $GITHUB_ENV
echo "LSAN_OPTIONS=suppressions=$GITHUB_WORKSPACE/ci/lsan.suppressions" >> $GITHUB_ENV
echo "int dlclose(void *p) { return 0; }" | cc -x c -shared -o libfake_dlclose.so -
echo "CI_LD_PRELOAD=$(echo /usr/lib/x86_64-linux-gnu/libasan.so.?):$(pwd)/libfake_dlclose.so" >> $GITHUB_ENV
echo "HWLOC_COMPONENTS=-cuda,-opencl,-rsmi" >> $GITHUB_ENV
- name: Run unit tests
timeout-minutes: 5
working-directory: ${{ env.build-dir }}
run: ${{ env.container-workspace }}/ci/run-unit-tests.sh
- name: Run examples (single-node)
timeout-minutes: 10
# We build examples twice, but only run the installed version (which probably has more failure modes)
working-directory: ${{ env.examples-build-dir }}
run: ${{ env.container-workspace }}/ci/run-examples.sh /data/Lenna.png 1
- name: Run examples (multi-node)
if: ${{ matrix.mpi }}
timeout-minutes: 10
working-directory: ${{ env.examples-build-dir }}
run: ${{ env.container-workspace }}/ci/run-examples.sh /data/Lenna.png 2 4
- name: Run debugging tests
if: matrix.build-type == 'Debug' && matrix.sycl != 'dpcpp' # newer DPC++ generates DWARF5 which is incompatible with Ubuntu 20.04's GDB
run: ${{ env.container-workspace }}/test/debug/pretty-print-test.py ${{ env.build-dir }}/test/debug/pretty_printables
- name: Run system tests
if: ${{ matrix.mpi }}
working-directory: ${{ env.build-dir }}
run: ${{ env.container-workspace }}/ci/run-system-tests.sh 2 4
- name: Run integration tests
working-directory: ${{ env.build-dir }}
run: ${{ env.container-workspace }}/test/integration/run-integration-tests.py . ${{ matrix.platform }}
- name: Upload stack traces (if any)
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.build-name }}
path: |
${{ env.build-dir }}/*.trace
${{ env.examples-build-dir }}/*.trace
if-no-files-found: ignore
- id: set-head-results
name: Set outputs for HEAD builds
if: matrix.sycl-version == 'HEAD'
run: |
echo "${{ matrix.sycl }}-HEAD-${{ matrix.build-type }}-works=1" >> "$GITHUB_OUTPUT"
echo "${{ matrix.sycl }}-HEAD-ubuntu-version=${{ matrix.ubuntu-version }}" >> "$GITHUB_OUTPUT"
- name: Collect & report coverage
if: matrix.build-type == 'Debug' && matrix.sycl == 'simsycl' # celerity-build/simsycl image enables --coverage for Debug builds
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
run: |
"${{ env.container-workspace }}/ci/capture-coverage.sh" "${{ env.container-workspace }}" "${{ env.build-dir }}" -o lcov.info
coveralls report lcov.info
# Tag "HEAD" images that built and tested successfully as "latest".
# This is only done for nightly builds (or when specifying the "tag-latest" option on manually triggered runs).
tag-latest-containers:
needs: build-and-test
# Run this step regardless of result of `build-and-test` (hence the `always()`),
# since we always want to tag images that were successful, even if others weren't.
if: always() && (github.event_name == 'schedule' || (inputs.test-head && inputs.tag-latest))
runs-on: slurm-${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
include:
- sycl: "dpcpp"
platform: "intel"
- sycl: "acpp"
platform: "nvidia"
env:
image-basename-dpcpp: ghcr.io/celerity/celerity-build/dpcpp:ubuntu${{ needs.build-and-test.outputs.dpcpp-HEAD-ubuntu-version }}
image-basename-acpp: ghcr.io/celerity/celerity-build/acpp:ubuntu${{ needs.build-and-test.outputs.acpp-HEAD-ubuntu-version }}
permissions:
packages: write
steps:
- name: Log into Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- if: matrix.sycl == 'dpcpp'
run: |
if [[ "${{ needs.build-and-test.outputs.dpcpp-HEAD-Debug-works }}" -eq 1 ]] && [[ "${{ needs.build-and-test.outputs.dpcpp-HEAD-Release-works }}" -eq 1 ]]; then
docker tag ${{ env.image-basename-dpcpp }}-HEAD ${{ env.image-basename-dpcpp }}-latest
docker push ${{ env.image-basename-dpcpp }}-latest
else
exit 1
fi
- if: matrix.sycl == 'acpp'
run: |
if [[ "${{ needs.build-and-test.outputs.acpp-HEAD-Debug-works }}" -eq 1 ]] && [[ "${{ needs.build-and-test.outputs.acpp-HEAD-Release-works }}" -eq 1 ]]; then
docker tag ${{ env.image-basename-acpp }}-HEAD ${{ env.image-basename-acpp }}-latest
docker push ${{ env.image-basename-acpp }}-latest
else
exit 1
fi
report:
needs: [build-and-test]
runs-on: [ self-hosted, slurm ]
env:
container-workspace: <placeholder>
container:
image: ghcr.io/celerity/celerity-lint
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Set container workspace environment variable
run: echo "container-workspace=$GITHUB_WORKSPACE" > $GITHUB_ENV
- uses: actions/checkout@v4
- name: Check code formatting
id: formatting
working-directory: ${{ env.container-workspace }}
shell: bash
run: |
unformatted=$("./ci/find-unformatted-files.sh")
{
echo 'unformatted-files<<EOF'
echo "$unformatted"
echo EOF
} >> "$GITHUB_OUTPUT"
- uses: "celerity/ci-report-action@v8"
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
unformatted-files: ${{ steps.formatting.outputs.unformatted-files }}