Skip to content

Improve GPU task correctness and benchmark integrity - #127

Merged
irvineoy merged 10 commits into
mainfrom
codex/rl-task-gpu-quality
Oct 20, 2026
Merged

irvineoy merged 10 commits into
mainfrom
codex/rl-task-gpu-quality

Conversation

@irvineoy

@irvineoy irvineoy commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Several tasks accepted incorrect candidates through fixed inputs, incomplete semantic coverage, or references computed from mutated inputs. Other tasks exposed host validation code through broad edit boundaries. This change repairs 114 task packages and adds regressions for those failure modes.

Runtime dependency: every task in this PR was validated only on the ROCm 10 image lmsysorg/sglang@sha256:e20849665c105d389ef91d23c0dc73931aaa6f02056dd10e7b43e4f16c79df69 (PyTorch 2.11, Triton 3.8, FlyDSL 0.3.2). #123 has since made this image the gfx950 default on main.

Changes

  • Restrict editable regions to device implementations while protecting host launch, reference, and comparison logic.
  • Add independent timed input draws and replay checks where fixed inputs allowed shortcuts; preserve input snapshots and restore state around candidate calls.
  • Extend correctness coverage for attention layouts and grouped heads, GDN modes, FLA/KDA geometry, convolution widths, quantization edge cases, and optional GEMM arguments.
  • Enforce candidate compute boundaries and import closure, retain compiled module owners, and fix grouped-attention head indexing.
  • Add a numerical GPU startup smoke check and focused CPU regressions, including compiler-portable fixtures and strict source-preservation checks.

Review fixes

  • Editable decorators: src/harness_guard.py rejects host callbacks (pre_hook, post_hook, prune_configs_by, perf_model, do_bench, launch_metadata), non-lambda heuristics values, and lambdas that do more than launch-metadata arithmetic. Every shipped baseline still passes the guard.

  • FlyDSL evaluator state (37 closure tasks and gemm_a8w8): candidates can no longer import the materialized timing helper _aka_benchmark, mutate imported modules (for example torch.cuda.Event.elapsed_time), read frame or function globals, reach sys through os.sys or builtins.__import__, or disable the PyTorch dispatch audit.

  • FlyDSL import closure: resolution follows Python's precedence (regular package, then same-name module, then namespace directory), and reassigned sys aliases converge in linear time.

  • gemm_a8w8: actual performance calls go through the candidate dispatch audit, and torch._scaled_mm is rejected.

  • SSD replay: the replay keeps the timed ×32 cb amplification instead of compounding it to ×1024.

  • New correctness-only controls (unscored):

    • triton_bmm: bf16/fp32, irregular dimensions, and strided/transposed/broadcast views.
    • triton_decode_attn_stage1 and triton_decode_attn_grouped_stage1: additional head widths, page sizes, group sizes, split counts and lengths.
    • triton_paged_prefix_prefill: head dims 16–128, page sizes, empty/unaligned lengths, windows.
    • chunk_local_cumsum: head_first and cu_seqlens/chunk_indices variants.
    • These task READMEs now state the supported domain derived from the protected wrappers.
  • Documentation:

    • 19 Triton READMEs note that the protected wrapper fixes the launch configuration.
    • fused_clamp_act_mul documents that N need not be a power of two.
    • dsv4_fp4_indexer documents that task-local helper modules are allowed.
    • Stale grid and case-count text is corrected.
  • Tests: the signal-distribution test reads originals from the base revision instead of HEAD, task import isolation restores sys.path, and the reviewed-history records cover the new bytes.

  • Release notes: docs/reference/release-notes.md states that some repaired tasks change their timed input distributions or invocation preparation, so their baselines must be recomputed and earlier scores are not directly comparable.

Scored cases, tolerances, warmups, sample counts and timing methods are unchanged by the review fixes.

Some repaired tasks intentionally change timed input distributions or invocation preparation. Recompute their baselines; old and new scores are not directly comparable. No speedup or model-training gain is claimed.

Validation

GPU (MI355X/gfx950, ROCm 10 image above):

  • All 114 modified task packages have source-matched, framework-finalized task_validator PASS reports.
    • The 58 packages changed by the review fixes were revalidated from scratch: 51 in the first round, and 7 more after their controls or text were added.
    • The other 56 packages are byte-identical to the originally validated sources.
    • Those 56 were validated before the stricter decorator guard. On CPU, the new guard still accepts every shipped baseline (437 tasks) and every prepared positive that the old guard accepted.
  • Prepared target-language positives pass compile, correctness and performance through the framework TaskSession for every changed task that has one. These runs exercise the new FlyDSL performance-mode audit and the gemm_a8w8 audit.
    • The chunk_local_cumsum positive was extended for the new variable-length controls.
    • triton_decode_attn_grouped_stage1 uses its implemented initial candidate.

CPU (macOS):

  • After rebasing onto main (Upgrade the MI355X default runtime to ROCm 10 #123 and the other merged changes; the only conflict was an append-only test file): full suite 18,563 passed. Every failure also fails on main on the same host, including one process-deadline test that fails intermittently there. make check-perf-helpers passes, and the task packages are unchanged from the validated sources.
  • Before the rebase: full suite 18,309 passed. The remaining failures are Linux-only tests that also fail on main on the same host, plus one known process-timing flake. The full Linux suite has not been rerun on the final tree; CI covers it.
  • tests/test_candidate_launch_and_state_boundaries.py reproduces each closed bypass. 84 of its 124 cases fail on the previous head.
  • make check-perf-helpers passes.

Known limitations and follow-ups

  • prepare_fn timing: it forces one graph replay per sample in gemm_a8w8 and four torch2hip tasks. Launch latency can dominate their smallest shapes.
  • hip2hip/matrix_multiplication inputs: they remain exactly representable in BF16, so a reduced-precision kernel can pass. This predates this PR.
  • Byte pins in tests/reviewed_contract_history.py: they still cover 45 Triton READMEs and configs, so documentation edits require regenerated records.
  • Fixed launch configuration: the protected wrappers now fix the Triton launch configuration (tiles, num_warps, num_stages) for the 19 symbol-scoped tasks. This narrows the optimization space. It is accepted for this PR so that the existing GPU reports stay valid; a follow-up PR will expose validated tile, warp and stage settings for these tasks and revalidate them.
  • FlyDSL tasks outside this PR: they still lack the timing-helper and evaluator-state protections added here; Harden task validation and repair across the remaining FlyDSL tasks #129 ports them.
  • Structural checks: the static and dispatch checks are task-contract enforcement, not a Python sandbox.

irvineoy and others added 10 commits October 20, 2026 15:26
Strengthen device edit boundaries, input integrity, semantic coverage, and
timed input variation across GPU task packages. Add focused regressions
and a numerical GPU startup smoke check.
Reject host callbacks and non-metadata lambdas in editable Triton
decorators, protect the timing helper and evaluator state in the FlyDSL
import closures, resolve same-name modules before namespace directories,
and make reassigned sys aliases converge linearly. Audit gemm_a8w8
performance calls, keep the SSD replay at the timed amplification, pin
the signal-distribution test to its base revision, and document the
protected launch configuration in the affected READMEs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fused clamp/act/mul wrapper supports any N >= 128 divisible by 128 by
padding to the next power of two, matching its declared D=3072 cases.
The dsv4 FP4 indexer README now states that task-local helper modules may
be added and pass the same closure and dependency checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The declared chunk_local_cumsum callable keeps head_first and
cu_seqlens/chunk_indices branches, but no manifest case exercised them.
Add nine correctness-only, untimed controls (records 11-19) that call the
actual operator with head_first=True (3D/4D), packed varlen sequences
(int32/int64 cu_seqlens, omitted/supplied chunk_indices, one-token and
non-multiple-of-64 lengths), and single-sequence head_first varlen, with
reverse/scale variants.

Each control computes an FP64 CPU reference from pristine clones before
the call, checks read-only g/cu_seqlens/chunk_indices, and uses the
existing output contract and atol=rtol=0.001 comparator. Each identity
runs base/changed/base draws in one allocation. Final-candidate calls go
through the existing per-call FlyDSL launch and preparation audit. The
task role rejects a manifest whose control rows differ from the protected
table. Multi-sequence head_first varlen stays out of the contract: the
retained kernels address it as packed [H,T_n] blocks, and upstream
callers reject it.

The ten scored cases, seeds, gates, warmups, samples, timing method and
the initial Triton source are unchanged. CPU validation only; this
change still needs a GPU task_validator run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The protected bmm_triton wrapper accepts any matching 3-D float16,
bfloat16 or float32 operands and forwards their strides, but the five
scored cases are fixed contiguous float16 shapes. Add eleven unscored
control-domain-* rows (case_index 20000-20010, checks [correctness])
from a protected task-root _domain_controls.py table covering bf16 and
fp32, B/M/N/K that are not multiples of the 128/128/32 (16-bit) and
64/64/32 (fp32) tiles, and transposed, batch-inner, padded-offset,
element-stride-2, batch-stride-2 and batch-broadcast operand views with
sentinel-filled gaps.

Each control computes an FP64 CPU reference from pristine clones before
the candidate call, requires unchanged input views and backing storage,
exact output shape/dtype/device, contiguous (M*N, N, 1) strides, finite
values and atol=rtol=1e-2. The adapter verifies the table and rows
against workloads.json; validate-task checks the oracle on CPU. Scored
rows, seeds, tolerances, warmups, samples, timing and the kernel are
unchanged; the runner change is one additive dispatch.

CPU-only validation (macOS, CPU torch, no Triton/GPU):
tests/test_bmm_domain_controls.py 149 passed. Expected pin failures:
test_vllm_v2_preserves_all_original_cases_checks_sources_and_helpers
[triton_bmm] (new dispatch) and
test_all_45_boundary_config_and_doc_inverses_require_exact_current_bytes
[triton_bmm/README.md] (new README bytes). No GPU task_validator run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The validator WARN flagged that the README promised arbitrary sequence
lengths, head dimensions, page sizes and group sizes, while the manifest
checked ten fixed cases. This change adds seven unscored controls, kept in
the protected _arena_domain_controls.py, that span the protected wrapper's
actual domain:
- groups 1/3/5/7/12/16/33 with 1, 2 or 3 KV heads
- Lk/Lv 16/16, 40/72, 80/80, 96/64, 128/128 and 256/256
- page sizes 1, 2, 3, 5, 12, 16 and 64
- splits 1 to 7, with inactive splits
- lengths 1 to 130 that end in a partial page and a partial BLOCK_N tile

The controls run through the existing run_contract_correctness path:
launch audit, NaN poisoning, read-only, metadata and alias checks,
byte-exact inactive slots, atol=rtol=0.01, and the unscored graph replay
with perturbed inputs. They compare against an independent float64 oracle
built from pristine clones, which maps query head h to KV head
h // kv_group_num. CallPlan, checked_modules and checked_benchmark accept
an optional oracle; the default is still expected_outputs, so scored cases
and earlier controls behave as before.

The README now states the real domain instead of "arbitrary". BLOCK_DPE is
always 0 in the wrapper, num_heads must be a multiple of num_kv_heads, and
tiles narrower than 16 or wider than 256 are not checked.

Scored rows, tolerances, warmups, samples, timing, the runner and the
kernel are unchanged.

CPU only (macOS, CPU torch, no Triton): the new test file passes, with 97
tests. It runs the actual wrapper and kernel bodies through a CPU tl
emulation. Two shared tests now fail by intent: the grouped README pin in
reviewed_contract_history, and the [7,6,5,4] page-prefix assertion in
test_new_decode_control_execution_and_declared_shapes, which assumed every
control uses eight reversed pages. No GPU validation yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Task validation failed because the README required "arbitrary" context
lengths, query lengths and head dimensions, while the manifest covered
only the five fixed scored tuples and two fixed ragged controls.

Add seven correctness-only controls in a protected _domain_controls.py
table, merged by _arena_checks.py into CONTRACT_CASES so they use the
existing manifest binding, adapter dispatch and public-wrapper checks:
pristine-input FP32 oracle rebuilt from cache bytes and the page table,
read-only/metadata guards, full-output 0.01 gates and the unscored
captured-replay diagnostic. They cover padded head dims 24/80/96/112
plus 16/32/128, pages 8/12/16/32/40/64/128 (both launch tile paths),
empty contexts and query segments, single-token queries, unaligned
lengths, queries spanning two M tiles, GQA 1-4/MQA, explicit
nondefault scales and windows 3/16/40/4096.

The README now states the evaluated domain precisely (float16, x = 8,
head_dim a multiple of 8 in 16..128) and lists the controls. Scored
rows, tolerances, warmups, samples, timing, runner and kernel are
unchanged.

CPU-only validation; no GPU run. A fresh task_validator pass on
compatible hardware is still required. The README byte pin in
tests/reviewed_contract_history.py needs updating.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README promised arbitrary sequence lengths, head dimensions and page
sizes, but the manifest covered only ten fixed configurations. Add seven
unscored control-domain-* rows (case indices 20000-20006) and state the
wrapper's actual supported domain precisely in the README.

The protected _domain_controls.py generator covers head dimensions 16-256
(including Lk > Lv and Lk < Lv), page sizes 1, 3, 5, 48, 64 and 128, split
counts 1-16 with inactive splits, and ragged lengths from 1 to 7999. It uses
seeded nonidentity page tables with decoy pages and tail slots. Each call
computes an independent FP64 CPU oracle from pristine clones, poisons
active outputs, requires inactive slots to stay byte-identical, rejects
read-only input or output metadata changes, and makes a second call on
the same tensors with rotated lengths and redrawn data. The runner
dispatches indices >= 20000 through the existing installed correctness
guard. The adapter binds the CASES table to the manifest rows and
validate-task self-checks the oracle.

Scored rows, tolerances, warmups, samples, timing and the kernel are
unchanged. CPU tests only; GPU task_validator has not been run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regenerate the exact README inverses, strip the additive protected
control dispatches before original-runner comparisons, account for the
correctness-only manifest rows, and register the chunk_local_cumsum
semantic-control harness delta. Scored rows and kernels stay pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Users comparing scores need to know that the repaired tasks change some timed
input distributions and invocation preparation, so baselines must be
recomputed and earlier scores are not directly comparable. Also note that the
symbol-scoped Triton tasks now fix their launch configuration.
@irvineoy
irvineoy force-pushed the codex/rl-task-gpu-quality branch from 9bbc7e7 to 2dae809 Compare October 20, 2026 22:28
@irvineoy
irvineoy marked this pull request as ready for review October 20, 2026 22:44
@irvineoy
irvineoy merged commit 6b6b6e3 into main Oct 20, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant