Skip to content

Commit 7ae656f

Browse files
committed
condense workflow
1 parent fee7bb8 commit 7ae656f

2 files changed

Lines changed: 196 additions & 186 deletions

File tree

.github/workflows/pr-comment-sweep.yml

Lines changed: 196 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,240 @@
1-
name: PR Comment Sweep
1+
name: Sweep
22

33
on:
4+
# PR comment trigger
45
issue_comment:
56
types: [created]
7+
# Manual trigger
8+
workflow_dispatch:
9+
inputs:
10+
pr-number:
11+
description: PR number to checkout (refs/pull/<num>/head)
12+
required: false
13+
type: string
14+
generator-args:
15+
description: Args passed to generate_sweep_configs.py (omit /sweep)
16+
required: false
17+
type: string
18+
# Push-based example/testing
19+
push:
20+
branches-ignore:
21+
- main
22+
- master
623

724
concurrency:
8-
group: "PR-SWEEP-${{ github.event.issue.number }}"
25+
group: ${{ github.event.issue.number && format('PR-SWEEP-{0}', github.event.issue.number) || format('REF-SWEEP-{0}', github.ref_name) }}
926
cancel-in-progress: true
1027

1128
permissions:
1229
contents: read
1330

1431
jobs:
15-
parse:
16-
# Run only for PR comments, from trusted authors, starting with /sweep
17-
if: >-
18-
${{ github.event.issue.pull_request &&
19-
startsWith(github.event.comment.body, '/sweep') &&
20-
contains('OWNER,MEMBER,COLLABORATOR', github.event.comment.author_association) }}
32+
prepare:
2133
runs-on: ubuntu-latest
2234
outputs:
23-
pr-number: ${{ steps.parse.outputs.pr-number }}
24-
generator-args: ${{ steps.parse.outputs.generator-args }}
35+
pr-number: ${{ steps.parse.outputs.pr-number || steps.resolve.outputs.pr-number }}
36+
generator-args: ${{ steps.parse.outputs.generator-args || steps.resolve.outputs.generator-args }}
2537
steps:
26-
- name: Derive PR number and parse command
38+
- name: Parse PR comment (/sweep ...)
2739
id: parse
40+
if: ${{ github.event_name == 'issue_comment' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/sweep') && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) }}
2841
shell: bash
2942
env:
3043
BODY: ${{ github.event.comment.body }}
3144
PR_NUMBER: ${{ github.event.issue.number }}
3245
run: |
3346
set -euo pipefail
34-
35-
# Extract first line starting with /sweep
36-
cmd_line=$(printf "%s" "$BODY" | awk '/^\/sweep/{print; exit}')
47+
# Allow optional leading whitespace before /sweep
48+
cmd_line=$(printf "%s" "$BODY" | awk '/^[[:space:]]*\/sweep/{print; exit}')
3749
if [[ -z "$cmd_line" ]]; then
3850
echo "No /sweep command found in comment" >&2
3951
exit 1
4052
fi
41-
cmd_args=${cmd_line#* /sweep}
42-
# Handle case when it's exactly '/sweep' (no args)
53+
# Trim leading spaces then strip the /sweep prefix
54+
cmd_line=$(echo "$cmd_line" | sed 's/^[[:space:]]*//')
4355
if [[ "$cmd_line" == "/sweep" ]]; then
4456
cmd_args=""
4557
else
4658
cmd_args=${cmd_line#/sweep}
4759
fi
4860
cmd_args=$(echo "$cmd_args" | xargs || true)
4961
50-
echo "Command args: $cmd_args"
51-
5262
echo "generator-args=$cmd_args" >> "$GITHUB_OUTPUT"
5363
echo "pr-number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
5464
55-
execute:
56-
needs: parse
57-
uses: ./.github/workflows/sweep-executor.yml
65+
- name: Find PR for this branch (if any)
66+
id: find
67+
if: ${{ github.event_name != 'issue_comment' }}
68+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
69+
with:
70+
script: |
71+
const owner = context.repo.owner;
72+
const repo = context.repo.repo;
73+
const branch = context.ref.replace('refs/heads/', '');
74+
const res = await github.rest.pulls.list({ owner, repo, state: 'open', head: `${owner}:${branch}` });
75+
const num = res.data[0]?.number ? String(res.data[0].number) : '';
76+
core.setOutput('pr-number', num);
77+
78+
- name: Prepare inputs (push/dispatch)
79+
id: resolve
80+
if: ${{ github.event_name != 'issue_comment' }}
81+
shell: bash
82+
env:
83+
DISPATCH_PR: ${{ github.event.inputs.pr-number }}
84+
DISPATCH_ARGS: ${{ github.event.inputs.generator-args }}
85+
run: |
86+
set -euo pipefail
87+
pr_from_branch='${{ steps.find.outputs.pr-number }}'
88+
pr_number="${DISPATCH_PR:-}"; if [[ -z "$pr_number" ]]; then pr_number="$pr_from_branch"; fi
89+
gen_args="${DISPATCH_ARGS:-}"
90+
if [[ -z "$gen_args" ]]; then
91+
gen_args='full-sweep --single-node --runner-type h200 --model-prefix dsr1 --seq-lens 1k1k --max-conc 4'
92+
fi
93+
echo "Resolved PR: $pr_number";
94+
echo "Using generator args: $gen_args";
95+
echo "pr-number=$pr_number" >> "$GITHUB_OUTPUT"
96+
echo "generator-args=$gen_args" >> "$GITHUB_OUTPUT"
97+
98+
generate:
99+
needs: prepare
100+
if: ${{ needs.prepare.outputs.pr-number != '' && needs.prepare.outputs.generator-args != '' }}
101+
runs-on: ubuntu-latest
102+
outputs:
103+
search-space-config: ${{ steps.generate.outputs.search-space-config }}
104+
is-multinode: ${{ steps.detect.outputs.is-multinode }}
105+
steps:
106+
- name: Checkout PR head
107+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
108+
with:
109+
ref: refs/pull/${{ needs.prepare.outputs.pr-number }}/head
110+
111+
- name: Detect node type from args
112+
id: detect
113+
run: |
114+
set -euo pipefail
115+
ARGS='${{ needs.prepare.outputs.generator-args }}'
116+
if [[ "$ARGS" == *"--multi-node"* ]]; then
117+
echo "is-multinode=true" >> "$GITHUB_OUTPUT"
118+
else
119+
echo "is-multinode=false" >> "$GITHUB_OUTPUT"
120+
fi
121+
122+
- name: Generate sweep configs
123+
id: generate
124+
shell: python
125+
env:
126+
GITHUB_WORKSPACE: ${{ github.workspace }}
127+
run: |
128+
import json, os, shlex, subprocess, sys
129+
130+
cmd_args = r'''${{ needs.prepare.outputs.generator-args }}'''
131+
script = os.path.join(os.environ['GITHUB_WORKSPACE'], 'utils', 'matrix_logic', 'generate_sweep_configs.py')
132+
cfg_amd = os.path.join(os.environ['GITHUB_WORKSPACE'], '.github', 'configs', 'amd-master.yaml')
133+
cfg_nv = os.path.join(os.environ['GITHUB_WORKSPACE'], '.github', 'configs', 'nvidia-master.yaml')
134+
runners = os.path.join(os.environ['GITHUB_WORKSPACE'], '.github', 'configs', 'runners.yaml')
135+
136+
subprocess.run([sys.executable, '-m', 'pip', 'install', 'pydantic'], check=True)
137+
138+
argv = [sys.executable, script]
139+
if cmd_args.strip():
140+
argv += shlex.split(cmd_args)
141+
argv += ['--config-files', cfg_amd, cfg_nv, '--runner-config', runners]
142+
143+
print('Invoking:', ' '.join(shlex.quote(a) for a in argv))
144+
res = subprocess.run(argv, capture_output=True, text=True)
145+
if res.returncode != 0:
146+
print('Generator failed. stdout:\n', res.stdout)
147+
print('stderr:\n', res.stderr, file=sys.stderr)
148+
raise SystemExit(res.returncode)
149+
150+
try:
151+
data = json.loads(res.stdout)
152+
except Exception as e:
153+
print('Failed to parse generator output as JSON:', e, file=sys.stderr)
154+
print('Raw output:\n', res.stdout)
155+
raise
156+
157+
print(f"Generated {len(data)} configs")
158+
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
159+
f.write('search-space-config=' + json.dumps(data) + '\n')
160+
161+
run-single-node:
162+
needs: generate
163+
if: ${{ needs.generate.result == 'success' && needs.generate.outputs.search-space-config != '[]' && needs.generate.outputs.is-multinode == 'false' }}
164+
uses: ./.github/workflows/benchmark-tmpl.yml
165+
name: Sweep (Single-Node)
166+
strategy:
167+
fail-fast: false
168+
matrix:
169+
config: ${{ fromJson(needs.generate.outputs.search-space-config) }}
170+
secrets: inherit
171+
with:
172+
exp-name: ${{ matrix.config.exp-name }}
173+
isl: ${{ matrix.config.isl }}
174+
osl: ${{ matrix.config.osl }}
175+
max-model-len: ${{ matrix.config.max-model-len }}
176+
runner: ${{ matrix.config.runner }}
177+
image: ${{ matrix.config.image }}
178+
model: ${{ matrix.config.model }}
179+
model-prefix: ${{ matrix.config.model-prefix }}
180+
framework: ${{ matrix.config.framework }}
181+
precision: ${{ matrix.config.precision }}
182+
tp: ${{ matrix.config.tp }}
183+
ep: ${{ matrix.config.ep }}
184+
dp-attn: ${{ matrix.config.dp-attn }}
185+
conc: ${{ matrix.config.conc }}
186+
spec-decoding: ${{ matrix.config.spec-decoding }}
187+
disagg: ${{ matrix.config.disagg }}
188+
189+
run-multi-node:
190+
needs: generate
191+
if: ${{ needs.generate.result == 'success' && needs.generate.outputs.search-space-config != '[]' && needs.generate.outputs.is-multinode == 'true' }}
192+
uses: ./.github/workflows/benchmark-multinode-tmpl.yml
193+
name: Sweep (Multi-Node)
194+
strategy:
195+
fail-fast: false
196+
matrix:
197+
config: ${{ fromJson(needs.generate.outputs.search-space-config) }}
198+
secrets: inherit
199+
with:
200+
exp-name: ${{ matrix.config.exp-name }}
201+
isl: ${{ matrix.config.isl }}
202+
osl: ${{ matrix.config.osl }}
203+
max-model-len: ${{ matrix.config.max-model-len }}
204+
runner: ${{ matrix.config.runner }}
205+
image: ${{ matrix.config.image }}
206+
model: ${{ matrix.config.model }}
207+
model-prefix: ${{ matrix.config.model-prefix }}
208+
framework: ${{ matrix.config.framework }}
209+
precision: ${{ matrix.config.precision }}
210+
conc-list: ${{ toJson(matrix.config.conc) }}
211+
spec-decoding: ${{ matrix.config.spec-decoding }}
212+
disagg: ${{ matrix.config.disagg }}
213+
214+
prefill-num-worker: ${{ matrix.config.prefill.num-worker }}
215+
prefill-tp: ${{ matrix.config.prefill.tp }}
216+
prefill-ep: ${{ matrix.config.prefill.ep }}
217+
prefill-dp-attn: ${{ matrix.config.prefill.dp-attn }}
218+
prefill-additional-settings: ${{ toJson(matrix.config.prefill.additional-settings) }}
219+
220+
decode-num-worker: ${{ matrix.config.decode.num-worker }}
221+
decode-tp: ${{ matrix.config.decode.tp }}
222+
decode-ep: ${{ matrix.config.decode.ep }}
223+
decode-dp-attn: ${{ matrix.config.decode.dp-attn }}
224+
decode-additional-settings: ${{ toJson(matrix.config.decode.additional-settings) }}
225+
226+
collect-results:
227+
needs: [run-single-node, run-multi-node]
228+
if: ${{ always() && (needs.run-single-node.result == 'success' || needs.run-multi-node.result == 'success') }}
229+
uses: ./.github/workflows/collect-results.yml
230+
name: Collect Results
58231
secrets: inherit
59232
with:
60-
pr-number: ${{ needs.parse.outputs.pr-number }}
61-
generator-args: ${{ needs.parse.outputs.generator-args }}
233+
exp-name: ''
62234

63235
note-ignored:
64236
# Inform when comment doesn't meet criteria (non-PR or not authorized)
65-
if: ${{ !github.event.issue.pull_request ||
66-
!startsWith(github.event.comment.body, '/sweep') ||
67-
!contains('OWNER,MEMBER,COLLABORATOR', github.event.comment.author_association) }}
237+
if: ${{ github.event_name == 'issue_comment' && (!github.event.issue.pull_request || !startsWith(github.event.comment.body, '/sweep') || !contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) }}
68238
runs-on: ubuntu-latest
69239
steps:
70240
- run: |

0 commit comments

Comments
 (0)