forked from radixark/miles
-
Notifications
You must be signed in to change notification settings - Fork 0
319 lines (304 loc) · 12.6 KB
/
Copy pathpr-test.yml
File metadata and controls
319 lines (304 loc) · 12.6 KB
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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# doc-dev: docs/ci/00-stage.md
# doc-dev: docs/ci/01-label.md
name: PR Test
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, labeled]
schedule:
# Nightly CI on main runs every enabled tag except long and ft-long, with fast-fail disabled.
# 15:00 UTC = 08:00 PDT / 07:00 PST (cron is UTC, no DST).
- cron: '0 15 * * *'
workflow_dispatch:
inputs:
infinite_run:
description: 'Run training infinitely'
required: false
type: boolean
default: false
ci_megatron_pr:
description: 'Megatron-LM branch/commit (default: miles-main)'
required: false
type: string
default: 'miles-main'
ci_sglang_pr:
description: 'SGLang branch/commit (default: sglang-miles)'
required: false
type: string
default: 'sglang-miles'
ci_image_tag:
description: 'Miles Docker image tag (default: dev)'
required: false
type: string
default: 'dev'
permissions:
contents: read
concurrency:
# PR updates supersede their previous run; distinct cron schedules and
# manual operations must not cancel one another on the default branch.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.schedule || github.run_id }}
cancel-in-progress: true
# `resolve-ci-policy` passes trigger-specific facts to `ci_policy.py`, which
# owns the explicit cadence, raw labels, test scope, and fast-fail policy.
# `run_suite.py` consumes that shared policy; GPU jobs consume the shared
# bypass output for their cross-stage gate.
#
# Trigger type is not policy: the current nightly cron is mapped by its exact
# expression, while workflow_dispatch remains a regular manual operation with
# no implicit domain scope.
jobs:
resolve-ci-policy:
runs-on: ubuntu-latest
outputs:
cadence: ${{ steps.resolve.outputs.cadence }}
raw_labels: ${{ steps.resolve.outputs.raw_labels }}
bypass_fastfail: ${{ steps.resolve.outputs.bypass_fastfail }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Resolve CI policy inputs
id: resolve
env:
EVENT_NAME: ${{ github.event_name }}
SCHEDULE: ${{ github.event.schedule || '' }}
PR_LABELS_JSON: ${{ toJSON(github.event.pull_request.labels.*.name) }}
run: python -m tests.ci.ci_policy
docker-paths:
runs-on: ubuntu-latest
outputs:
changed: ${{ steps.diff.outputs.changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
persist-credentials: false
- id: diff
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || '' }}
run: |
# Cron and manual runs have no PR diff and never build a PR image.
if [ -z "$BASE_SHA" ]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Compare the PR merge commit with its current base (HEAD^1) rather than
# the recorded base.sha, which can lag main and pull in unrelated changes.
# Dockerfile.rocm doesn't feed the cu13 multi-arch build this pipeline produces.
if git diff --name-only HEAD^1 HEAD \
| grep -qE '^(docker/(Dockerfile|build\.py|verify_transformer_engine\.py)|requirements\.txt)$|^docker/patch/'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
# Docker PRs: build the multi-arch image first and run every suite inside it.
# Always runs: with nothing to build every step is a no-op and it stays off the
# GPU fleet.
docker-build:
needs: [docker-paths]
if: always() && !cancelled()
runs-on: ${{ fromJSON((needs.docker-paths.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository) && '["h200", "2gpu"]' || '["ubuntu-latest"]') }}
timeout-minutes: 180
outputs:
built: ${{ steps.build.outputs.built || 'false' }}
env:
# Forks cannot push to the registry, so they keep the released image.
BUILD: ${{ needs.docker-paths.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
steps:
- name: Checkout repository
if: env.BUILD == 'true'
uses: actions/checkout@v4
- name: Set up Docker Buildx
if: env.BUILD == 'true'
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=moby/buildkit:latest
network=host
- name: Install Python + dependencies
if: env.BUILD == 'true'
run: |
apt-get update && apt-get install -y python3 python3-pip
pip3 install --break-system-packages typer
- name: Login to Docker Hub
if: env.BUILD == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push PR tag
id: build
if: env.BUILD == 'true'
run: |
python3 docker/build.py --variant cu13 --image-tag custom \
--custom-tag pr-${{ github.event.pull_request.number }} --push
echo "built=true" >> "$GITHUB_OUTPUT"
- name: Nothing to build
if: env.BUILD != 'true'
run: echo "No docker-relevant changes; suites use the released image."
# No `if:` guard: a real build failure must stop the suites rather than run them
# against a stale image.
resolve-ci-image:
needs: [docker-build]
runs-on: ubuntu-latest
outputs:
container_image: ${{ steps.resolve.outputs.container_image }}
steps:
- name: Resolve CI image
id: resolve
shell: bash
env:
PR_BODY: ${{ github.event.pull_request.body || '' }}
INPUT_CI_IMAGE_TAG: ${{ github.event.inputs.ci_image_tag || '' }}
DOCKER_BUILT: ${{ needs.docker-build.outputs.built }}
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
run: |
CI_IMAGE_TAG="${INPUT_CI_IMAGE_TAG}"
[ -z "$CI_IMAGE_TAG" ] && [ "$DOCKER_BUILT" = "true" ] && CI_IMAGE_TAG="pr-${PR_NUMBER}"
if [ -n "$PR_BODY" ]; then
PR_CI_IMAGE_TAG=$(echo "$PR_BODY" | grep -m1 -oP '^ci-image-tag:\s+\K\S+' || true)
[ -z "$CI_IMAGE_TAG" ] && [ -n "$PR_CI_IMAGE_TAG" ] && CI_IMAGE_TAG="$PR_CI_IMAGE_TAG"
fi
[ -z "$CI_IMAGE_TAG" ] && CI_IMAGE_TAG="dev"
if [[ ! "$CI_IMAGE_TAG" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]]; then
echo "::error::ci-image-tag must be a Docker tag, not a full image name: $CI_IMAGE_TAG"
exit 1
fi
echo "container_image=radixark/miles:${CI_IMAGE_TAG}" >> "$GITHUB_OUTPUT"
echo "Resolved CI image: radixark/miles:${CI_IMAGE_TAG}"
# Stage A: CPU-only fast tests (always runs on PR)
# Runs on GitHub-hosted ubuntu-latest (cpu_runner: true) to avoid
# occupying GPU-fleet runner slots.
stage-a-cpu:
needs: [resolve-ci-policy, resolve-ci-image]
strategy:
fail-fast: false
matrix:
partition_id: [0, 1, 2, 3]
uses: ./.github/workflows/_run-ci.yml
with:
cpu_runner: true
execute_command: >-
python tests/ci/run_suite.py --hw cpu --suite stage-a-cpu
--auto-partition-id ${{ matrix.partition_id }} --auto-partition-size 4
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
# Stage B: CPU-only bucket for slower CPU tests that don't fit stage-a-cpu's
# fast budget. Always runs on PR; an empty suite still exits 0 in run_suite.py.
stage-b-cpu:
needs: [resolve-ci-policy, resolve-ci-image]
uses: ./.github/workflows/_run-ci.yml
with:
cpu_runner: true
execute_command: >-
python tests/ci/run_suite.py --hw cpu --suite stage-b-cpu
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
stage-b-2-gpu-h200:
needs: [resolve-ci-policy, resolve-ci-image, stage-a-cpu]
if: |
always() && !cancelled() &&
needs.resolve-ci-policy.result == 'success' &&
needs.resolve-ci-image.result == 'success' &&
(needs.stage-a-cpu.result == 'success' ||
(needs.stage-a-cpu.result == 'failure' && needs.resolve-ci-policy.outputs.bypass_fastfail == 'true'))
uses: ./.github/workflows/_run-ci.yml
with:
runs_on: '["h200", "2gpu"]'
container_image: ${{ needs.resolve-ci-image.outputs.container_image }}
execute_command: >-
python tests/ci/run_suite.py --hw cuda --suite stage-b-2-gpu-h200
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
stage-c-8-gpu-h100:
needs: [resolve-ci-policy, resolve-ci-image, stage-a-cpu]
if: |
always() && !cancelled() &&
needs.resolve-ci-policy.result == 'success' &&
needs.resolve-ci-image.result == 'success' &&
(needs.stage-a-cpu.result == 'success' ||
(needs.stage-a-cpu.result == 'failure' && needs.resolve-ci-policy.outputs.bypass_fastfail == 'true'))
strategy:
fail-fast: false
matrix:
partition_id: [0, 1]
uses: ./.github/workflows/_run-ci.yml
with:
runs_on: '["h100", "8gpu"]'
container_image: ${{ needs.resolve-ci-image.outputs.container_image }}
execute_command: >-
python tests/ci/run_suite.py --hw cuda --suite stage-c-8-gpu-h100
--auto-partition-id ${{ matrix.partition_id }} --auto-partition-size 2
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
stage-c-8-gpu-h200:
needs: [resolve-ci-policy, resolve-ci-image, stage-a-cpu]
if: |
always() && !cancelled() &&
needs.resolve-ci-policy.result == 'success' &&
needs.resolve-ci-image.result == 'success' &&
(needs.stage-a-cpu.result == 'success' ||
(needs.stage-a-cpu.result == 'failure' && needs.resolve-ci-policy.outputs.bypass_fastfail == 'true'))
strategy:
fail-fast: false
matrix:
partition_id: [0, 1]
uses: ./.github/workflows/_run-ci.yml
with:
runs_on: '["h200", "8gpu"]'
container_image: ${{ needs.resolve-ci-image.outputs.container_image }}
execute_command: >-
python tests/ci/run_suite.py --hw cuda --suite stage-c-8-gpu-h200
--auto-partition-id ${{ matrix.partition_id }} --auto-partition-size 2
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
stage-c-4-gpu-h200:
needs: [resolve-ci-policy, resolve-ci-image, stage-a-cpu]
if: |
always() && !cancelled() &&
needs.resolve-ci-policy.result == 'success' &&
needs.resolve-ci-image.result == 'success' &&
(needs.stage-a-cpu.result == 'success' ||
(needs.stage-a-cpu.result == 'failure' && needs.resolve-ci-policy.outputs.bypass_fastfail == 'true'))
strategy:
fail-fast: false
matrix:
partition_id: [0, 1, 2]
uses: ./.github/workflows/_run-ci.yml
with:
runs_on: '["h200", "4gpu"]'
container_image: ${{ needs.resolve-ci-image.outputs.container_image }}
execute_command: >-
python tests/ci/run_suite.py --hw cuda --suite stage-c-4-gpu-h200
--auto-partition-id ${{ matrix.partition_id }} --auto-partition-size 3
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit
stage-c-2-gpu-h200:
needs: [resolve-ci-policy, resolve-ci-image, stage-a-cpu]
if: |
always() && !cancelled() &&
needs.resolve-ci-policy.result == 'success' &&
needs.resolve-ci-image.result == 'success' &&
(needs.stage-a-cpu.result == 'success' ||
(needs.stage-a-cpu.result == 'failure' && needs.resolve-ci-policy.outputs.bypass_fastfail == 'true'))
strategy:
fail-fast: false
matrix:
partition_id: [0, 1]
uses: ./.github/workflows/_run-ci.yml
with:
runs_on: '["h200", "2gpu"]'
container_image: ${{ needs.resolve-ci-image.outputs.container_image }}
execute_command: >-
python tests/ci/run_suite.py --hw cuda --suite stage-c-2-gpu-h200
--auto-partition-id ${{ matrix.partition_id }} --auto-partition-size 2
--cadence ${{ needs.resolve-ci-policy.outputs.cadence }}
--labels ${{ needs.resolve-ci-policy.outputs.raw_labels }}
secrets: inherit