Repository navigation
Conversation
…ules with its functions, so a rewrite that uses one (struct in PR seedds#1902's hfma_msl) runs as it does in a build instead of raising NameError
|
I ran this branch through the Orin value test from #2041, together with #2049. ptxas compiles No regressions. Of the 193 ops, the only one that changes against main plus #2049 is Your rewrite covers HFMA2.MMA too. Its MSL has the same shape as HFMA2's, and It doesn't fire on Could What this can't confirm. The fixture has 1,024 cases per op and none of the rare double-rounding inputs, so it doesn't prove the single rounding itself. Your 4,570-case fixture does that. What it does show is that nothing else moves. Running it also turned up a bug in my test: it didn't give the rewrites To rerun once #2041 is in: |
|
A heads-up about an interaction with #1774 (the shader loop guard), which I hit when I put this PR and #1774 on one branch together. Neither breaks on its own, but whichever lands second will.
Your test doesn't see it because its kernels don't go through The fix I used, at the end of return re.sub(r'(\n uint dm_lg = 0u;[^\n]*)((?:\n#pragma [^\n]*)+)', r'\2\1', '\n'.join(out))With that, this PR and #1774 build together, and |
…ules with its functions, so a rewrite that uses one (struct in PR seedds#1902's hfma_msl) runs as it does in a build instead of raising NameError (cherry picked from commit 5a7bf54)
…eps a function's leading #pragma lines first so that helper compiles beside PR seedds#1774's loop guard (PR seedds#1902), with this branch's translator rebuilt from its own source; chain 681014b2ecf1
ac76a7a to
6e08938
Compare
|
thanks for running it through the orin suite. rebased on main, and hfma_msl now also takes the isnan(v) ? v : max(v, 0) form, so you can keep .RELU as it is in #2049. moved the pragmas into a block of their own inside the helper, so a line loop_guard puts at the top of the body can't break them, whichever lands first. added tests for both |
…ules with its functions, so a rewrite that uses one (struct in PR seedds#1902's hfma_msl) runs as it does in a build instead of raising NameError (cherry picked from commit 5a7bf54)
…lf ULP off to 0, 99.9967 to 100 percent identical) The translator writes HFMA2 as fma(a, b, c) in float on the unpacked halves and packs with half2(float2(..)): two roundings. Measured against a Jetson Orin (sm_87, PTX fma.rn.f16x2, 1,048,576 random triples + 24,389 edge ones), 39 + 31 lanes of 1,048,576 each way differ by one half ULP (-3136 * -8.125 + 0.000124693: Orin 25488, Metal 25472). dmsh_build.py hfma_msl rewrites the fma whose three operands are halves (unpacked, negated, or a literal a half holds) and whose every use ends in a pack to half (through .SAT's clamp and .RELU's max) to dmsh_hfma: the float result rounded to odd, from a TwoSum of the exact product and the addend, so the conversion to half rounds the exact value once. The helper carries `#pragma METAL fp math_mode(safe)` and contract(off): without them fast math folds the TwoSum and 26 of the 70 lanes stay wrong (17 + 9). An FFMA then F2FP and HFMA2.F32 are left alone (the hardware rounds twice there as well). Translator binary and lock unchanged. After: 0 of 2,097,152 lanes differ (100 percent), same in default, fast, safe and relaxed math. Cost: a 16M-element kernel 45.6-48.0 vs 47.1-47.9 ps an element (memory bound, same); 34 of 244 fmas of an Ocarina of Time shader rewritten, +592 bytes of AIR. dmsh_chain.h moves to acdba0750359. test_dmsh_hfma.py: the rewrite, and on the GPU 4570 Orin outputs (the 70 differing triples, 3000 random, 1500 edge; numbers only in hfma_orin_fixture.u32) in every math mode; the old kernel fails the same 70.
6e08938 to
843a35b
Compare
…nds once to half), seedds#1909 (fragment uniform reads bound to the binding length), seedds#1901 (dispatch_overlap on for Ocarina), seedds#1459 (MetalFX takes agl_ndsr_vr, no-curve variants linear), seedds#1903 (render scale stubs for Ocarina; replaces the seedds#1497 ceiling we carried) Hand-resolved: the mesh draw keeps the task isolation of seedds#1842 and the copy paths our nvn_tex_level_range / DM_SHARPEN; seedds#1497's stub, test and BINDING entry go; the build-keyed rule names the render scale function (main+0x31d3200). Chain e906c7467690. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014eD437mxrMnW2UwLZhpwc7 Upstream pull requests applied in this commit (their authors' work, brought onto this tree with a three-way merge; the description is in each PR): - seedds#1459 by PromethOps (open): DM_UPSCALER=metalfx takes agl's agl_ndsr_vr.pck networks too, and a variant with no curve and no power is drawn as one colour space: Ocarina of Time's upscaler is MetalFX's - seedds#1497 by givethesourceplox (open): Add a render-scale ceiling for Ocarina v131072 - seedds#1842 by ycarogabriel-lgtm (open): Ocarina of Time: opt-in task isolation (DM_NVN_ISOLATE_TASK), the Hi-Z task a5288 in command buffers of its own, a workaround for its GPU hangs on an M1 - seedds#1897 by Know-It-All-Brother (closed): HMMA with an f16 accumulator rounds once per 8 products, as Ampere does (chain change) - seedds#1901 by FifteenPen (open): The game's compute dispatches with no game barrier between them run side by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 → 14.76 ms - seedds#1902 by fxd0h (open): HFMA2 rounds once to half, as Ampere does (chain change) - seedds#1903 by FifteenPen (open): Ocarina of Time takes the launcher's Render scale: the 3D views at that fraction of the game's own size, the dynamic resolution held at its top level (Kokiri Forest docked at 0.75: GPU p50 15.77 → 14.31 ms, 60 fps held) - seedds#1909 by oz-rinkliff (open): Bound translated fragment uniform reads to the NVN binding length
…1909 seedds#1897 seedds#1917 seedds#1920 seedds#1936) and seedds#1902, ahead of merging main Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014eD437mxrMnW2UwLZhpwc7 Upstream pull requests applied in this commit (their authors' work, brought onto this tree with a three-way merge; the description is in each PR): - seedds#1897 by Know-It-All-Brother (closed): HMMA with an f16 accumulator rounds once per 8 products, as Ampere does (chain change) - seedds#1902 by fxd0h (open): HFMA2 rounds once to half, as Ampere does (chain change) - seedds#1909 by oz-rinkliff (open): Bound translated fragment uniform reads to the NVN binding length - seedds#1917 by FifteenPen (closed): A draw that writes depth and samples its own depth attachment reads a copy of it: Ocarina of Time's light-blue dashes over the rock at Death Mountain Trail's cave entrance are gone - seedds#1920 by nawangwe (closed): A GPU-written span's sliver inside a texture does not make it the GPU's: Ocarina of Time's terrain tiles no longer vanish or show another tile's surface (seedds#1566) - seedds#1936 by TheGoldfish11 (closed): Write resolution-family image textures uncompressed
What and why
The translator writes HFMA2 as
fma(a, b, c)on the halves unpacked to float, then packs withhalf2(float2(..)): two roundings. The hardware roundsa * b + conce. Measured on a Jetson Orin (sm_87, PTXfma.rn.f16x2) on Nov 7, 70 of 2,097,152 lanes were one half ULP off (99.9967% identical). For example, -3136 × -8.125 + 0.000124693 gives 25488 on the Orin and 25472 on Metal.hfma_mslrewrites a half-onlyfmathat is packed back to half intodmsh_hfma. That helper rounds the float result to odd from a TwoSum, so the conversion to half rounds once. It's compiled in safe math with contraction off, because fast math folds the TwoSum. FFMA → F2FP and HFMA2.F32 are left alone, since the hardware rounds twice there as well. Reference entry: HFMA2 rounds twice to half.Checked
test_dmsh_hfma.py(8 tests). Its fixture holds 1,500 of the Orin's edge triples plus the 70 lanes. After the change, 0 of 2,097,152 lanes differ, in default, fast, safe and relaxed math.test_dmsh_hmma.py,test_nsp_chain.pyandtest_docs.pyalso pass.