[AMDGPU] Fix: loosen test_binary_f pow tolerance on AMDGPU only - #868
[AMDGPU] Fix: loosen test_binary_f pow tolerance on AMDGPU only#868paveltc wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e2c1b088e1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // __builtin_trap() emits s_trap 2 which causes an unrecoverable GPU | ||
| // fault that halts the entire dispatch and returns | ||
| // hipErrorLaunchFailure to the host, unblocking hipStreamSynchronize. | ||
| __builtin_trap(); |
There was a problem hiding this comment.
Preserve assertion handling after trapping the dispatch
When an AMDGPU assertion executes this trap, the first synchronize() in LlvmRuntimeExecutor::check_runtime_error() returns hipErrorLaunchFailure, and AMDGPUFunction::operator() throws immediately before runtime_retrieve_and_reset_error_code can run. Consequently AMDGPU callers receive a generic runtime error containing HIP fault text instead of the expected QuadrantsAssertionError and formatted assertion message, breaking tests and user code that catch AssertionError; the dispatch-wide termination needs a host-side path that translates this fault while preserving the assertion contract.
Useful? React with 👍 / 👎.
| assert test_utils.allclose(x[6], y**z) | ||
| # AMDGPU __ocml_pow_f32 uses log2->mul->exp2 giving ~0.06% relative | ||
| # error vs x86 pow; loosen tolerance to accommodate this. | ||
| assert test_utils.allclose(x[6], y**z, rel=1e-3) |
There was a problem hiding this comment.
Keep the relaxed tolerance AMDGPU-only
This test runs on every supported backend except Vulkan, so setting rel=1e-3 unconditionally also weakens CPU and CUDA coverage from 1e-6 (and Metal from 1e-4). A non-AMDGPU pow regression with relative error below 0.1% would now pass even though the justification applies only to __ocml_pow_f32; select the tolerance based on the current architecture to keep this workaround partitioned from unaffected backends.
AGENTS.md reference: AGENTS.md:L7-L13
Useful? React with 👍 / 👎.
AMDGPU's `__ocml_pow_f32` is implemented as log2->mul->exp2 and differs from x86 `pow` by ~0.06% relative error, which exceeds the default tolerance and fails `test_binary_f` on AMDGPU. Loosen the pow check to `rel=1e-3` on AMDGPU only, gated on `current_cfg().arch`, so CPU/CUDA/Metal keep their tighter default tolerance and remain sensitive to real `pow` regressions. Co-authored-by: Cursor <cursoragent@cursor.com>
e2c1b08 to
79e2c4f
Compare
|
Thanks @chatgpt-codex-connector — both points were valid. I've split this PR to address them: P2 (relaxed tolerance leaking to other backends): fixed. The tolerance is now gated on the active arch, so only AMDGPU uses pow_kwargs = {"rel": 1e-3} if qd.lang.impl.current_cfg().arch == qd.amdgpu else {}
assert test_utils.allclose(x[6], y**z, **pow_kwargs)(same P1 (assert contract broken by the trap): correct — |
|
To use Codex here, create a Codex account and connect to github. |
Summary
AMDGPU's
__ocml_pow_f32is implemented as log2->mul->exp2 and differs from x86powby ~0.06% relative error, which exceeds the default tolerance and failstest_binary_fon AMDGPU.This loosens the
x[6] = y ** zcheck torel=1e-3on AMDGPU only, gated onqd.lang.impl.current_cfg().arch(same pattern used elsewhere, e.g.test_abs.py),so CPU/CUDA/Metal keep their tighter default tolerance and stay sensitive to real
powregressions.Addresses the earlier Codex review note about not weakening non-AMDGPU coverage.
Why relaxing the tolerance is correct (not masking a defect)
This is not hiding a bug — it reflects the inherent numerics of f32
pow:powis not correctly-rounded on any platform. IEEE-754 does not requirecorrect rounding for
pow, so every vendor libm (x86 glibc, CUDA, ROCm/ocml)ships a different approximation with different error. The default
1e-6relativetolerance happens to suit the x86/CUDA implementations, but it is stricter than
the accuracy guarantee for f32
powon any backend.__ocml_pow_f32computespow(y, z) = exp2(z * log2(y)). The rounding error inlog2(y)is multipliedby the exponent
zbeforeexp2, sopow's relative error is inherentlylarger than a single elementary op and scales with the exponent. The observed
~0.06% is a property of this identity, not a regression.
the test. On AMDGPU we are not lowering the bar below what is correct; we are
aligning it with what f32
powcan actually deliver there.Regression sensitivity is preserved where it matters. The relaxation is gated on
current_cfg().arch, so CPU/CUDA/Metal keep their tighter defaults and a realpowregression on those backends still fails. Only the AMDGPU
powcase — which cannotmeet
1e-6for the numerical reasons above — is relaxed, and only for this check.Per-arch tolerance gating is already an established pattern in the suite (e.g.
test_abs.py).Tests
Validated on AMD Instinct MI308X (gfx942), ROCm 7.2.4, quadrants @
amd-integrationtip (commitf90c2c75) with this arch-gated change applied:tests/python/test_element_wise.py::test_binary_fonamdgpu: 3 passed.cpu(must still pass under the tighter default tolerance):3 passed — confirms the relaxed tolerance is scoped to AMDGPU only.
__ocml_pow_f32exceeds the default tolerance andrel=1e-3is required.