Add DLSS accuracy mode and GLIBC 2.41 release builds
- Add default-off PreferAccuracy for all native kernel families, including RDNA4 FP8 variants. - Restore intermediate FP8 quantization, per-MMA FP16 rounding, denormal handling and NGX synchronization in accuracy mode. - Select separately marked accuracy kernels and use a separate JIT cache; reject mixed sets and never silently substitute fast kernels. - Add a pinned GLIBC 2.41 build environment for ZLUDA/LLVM, the DLLs and both kernel sets, with ABI checks and toolchain provenance. - Support parallel target builds and pre-extracted PTX; correct ROCm header paths and Clang-CL input handling. - Bump to 0.1.3 and update release notes, documentation and tests. Validation: 11 tests passed; all 912 kernels built; E/K/M GPU harness runs completed with accuracy off/on. Packaged libraries loaded under GLIBC 2.41 and require no GLIBC version newer than 2.38. RTX image-quality parity remains unverified. Fixes #6 Refs #6
This commit is contained in:
1 parent
b2b3781aca
commit
b645ef9096
25 files changed
+641
-105
No files matched your search
@@ -0,0 +1,165 @@
|
||||
"""CPU checks for accuracy policy, config precedence and native-set selection.
|
||||
|
||||
Run: python3 -m unittest discover -s tests -v
|
||||
Kernel arithmetic additionally needs kernel/model replays and an RTX reference.
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
POLICY = ("D4R_ZLUDA_IGNORE_DENORMAL", "D4R_ZLUDA_WMMA_F32ACC", "D4R_ZLUDA_FAST_MATH",
|
||||
"D4R_ZLUDA_WAVE64", "D4R_ELIDE_NGX_SYNC")
|
||||
|
||||
|
||||
class AccuracyTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.build = tempfile.TemporaryDirectory()
|
||||
cls.runner = Path(cls.build.name) / "selection"
|
||||
source = r'''
|
||||
#include "d4r_native_selection.h"
|
||||
int main(int argc, char** argv) {
|
||||
if (argc == 2 && strcmp(argv[1], "policy") == 0) {
|
||||
printf("%d", d4r_apply_accuracy_policy());
|
||||
const char* keys[] = {"D4R_ZLUDA_IGNORE_DENORMAL", "D4R_ZLUDA_WMMA_F32ACC",
|
||||
"D4R_ZLUDA_FAST_MATH", "D4R_ZLUDA_WAVE64", "D4R_ELIDE_NGX_SYNC"};
|
||||
for (unsigned i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i)
|
||||
printf(" %s", getenv(keys[i]) ? getenv(keys[i]) : "unset");
|
||||
puts("");
|
||||
return 0;
|
||||
}
|
||||
if (argc != 5) return 2;
|
||||
char path[1024] = {0};
|
||||
int kind = d4r_select_native_source(argv[1], argv[2], atoi(argv[3]), atoi(argv[4]), path, sizeof(path));
|
||||
printf("%d %s\n", kind, path);
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
subprocess.run(["cc", "-x", "c", "-std=gnu11", "-Wall", "-Wextra", "-Werror",
|
||||
"-I", str(ROOT / "tools"), "-o", str(cls.runner), "-"],
|
||||
input=source, text=True, check=True, capture_output=True)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.build.cleanup()
|
||||
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
|
||||
def native(self, directory, accuracy=False, manifest=True):
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
(directory / "kernel.hsaco").write_bytes(b"fixture")
|
||||
if manifest:
|
||||
(directory / "d4r-kernels.txt").write_text("kernel 1234\n")
|
||||
if accuracy:
|
||||
(directory / "d4r-accuracy.txt").write_text("1\n")
|
||||
|
||||
def select(self, architecture="gfx1101", accuracy=True, fp8=True, directory=None):
|
||||
output = subprocess.check_output([str(self.runner), str(directory or self.root), architecture,
|
||||
str(int(accuracy)), str(int(fp8))], text=True).strip()
|
||||
kind, _, path = output.partition(" ")
|
||||
return int(kind), Path(path)
|
||||
|
||||
def test_select_accuracy_for_every_release_target(self):
|
||||
for arch in ("gfx1100", "gfx1101", "gfx1102", "gfx1103", "gfx1200", "gfx1201"):
|
||||
self.native(self.root / arch)
|
||||
accurate = self.root / "accuracy" / arch
|
||||
self.native(accurate, accuracy=True)
|
||||
self.assertEqual(self.select(arch), (1, accurate))
|
||||
self.assertEqual(self.select(arch, accuracy=False), (1, self.root / arch))
|
||||
|
||||
def test_rdna4_fp8_selection_and_widened_fallback(self):
|
||||
for arch in ("gfx1200", "gfx1201"):
|
||||
accurate = self.root / "accuracy" / arch
|
||||
fp8 = self.root / "accuracy" / (arch + "-fp8")
|
||||
self.native(accurate, accuracy=True)
|
||||
self.assertEqual(self.select(arch), (1, accurate))
|
||||
self.native(fp8, accuracy=True)
|
||||
self.assertEqual(self.select(arch), (1, fp8))
|
||||
self.assertEqual(self.select(arch, fp8=False), (1, accurate))
|
||||
|
||||
def test_missing_accuracy_never_selects_fast_or_wrong_gpu(self):
|
||||
self.native(self.root / "gfx1101")
|
||||
self.native(self.root / "accuracy" / "gfx1201", accuracy=True)
|
||||
self.assertEqual(self.select()[0], 0)
|
||||
self.native(self.root / "accuracy" / "gfx1101") # unmarked binaries
|
||||
self.assertEqual(self.select()[0], 0)
|
||||
|
||||
def test_flat_accuracy_developer_set_requires_valid_marker(self):
|
||||
self.native(self.root, manifest=False)
|
||||
self.assertEqual(self.select()[0], 0)
|
||||
self.assertEqual(self.select(accuracy=False), (2, self.root))
|
||||
(self.root / "d4r-accuracy.txt").write_text("1\n")
|
||||
self.assertEqual(self.select(), (2, self.root))
|
||||
(self.root / "d4r-accuracy.txt").write_text("0\n")
|
||||
self.assertEqual(self.select()[0], 0)
|
||||
|
||||
def test_missing_fast_target_does_not_select_release_root(self):
|
||||
self.native(self.root / "gfx1201")
|
||||
self.assertEqual(self.select(accuracy=False)[0], 0)
|
||||
|
||||
def test_accuracy_policy_overrides_conflicting_fast_settings(self):
|
||||
env = dict(os.environ, D4R_PREFER_ACCURACY="1", **dict.fromkeys(POLICY, "1"))
|
||||
output = subprocess.check_output([str(self.runner), "policy"], env=env, text=True).strip()
|
||||
self.assertEqual(output, "1 0 0 0 0 0")
|
||||
|
||||
def test_default_off_preserves_existing_policy(self):
|
||||
env = {k: v for k, v in os.environ.items() if k != "D4R_PREFER_ACCURACY"}
|
||||
env.update(dict.fromkeys(POLICY, "1"))
|
||||
output = subprocess.check_output([str(self.runner), "policy"], env=env, text=True).strip()
|
||||
self.assertEqual(output, "0 1 1 1 1 1")
|
||||
|
||||
def config(self, text, extra_env=None, expected=0):
|
||||
path = self.root / "d4r.ini"
|
||||
path.write_text(text)
|
||||
env = {k: v for k, v in os.environ.items() if not k.startswith("D4R_")}
|
||||
env.update(extra_env or {})
|
||||
result = subprocess.run(["python3", str(ROOT / "scripts/d4r_config.py"), "--config", str(path)],
|
||||
env=env, text=True, capture_output=True)
|
||||
self.assertEqual(result.returncode, expected, result.stderr)
|
||||
return result
|
||||
|
||||
def test_config_default_and_boolean_spellings(self):
|
||||
self.assertIn("export D4R_PREFER_ACCURACY=0", self.config("").stdout)
|
||||
for value in ("true", "on", "yes", "1"):
|
||||
result = self.config(f"[Kernels]\nPreferAccuracy = {value}\nNativeKernels = off\n")
|
||||
self.assertIn("export D4R_PREFER_ACCURACY=1", result.stdout)
|
||||
self.assertNotIn("D4R_ZLUDA_NATIVE_DIR", result.stdout)
|
||||
for value in ("false", "off", "no", "0"):
|
||||
self.assertIn("export D4R_PREFER_ACCURACY=0",
|
||||
self.config(f"[Kernels]\nPreferAccuracy = {value}\n").stdout)
|
||||
|
||||
def test_explicit_environment_wins_and_invalid_setting_is_reported(self):
|
||||
self.assertNotIn("export D4R_PREFER_ACCURACY",
|
||||
self.config("[Kernels]\nPreferAccuracy=true\n", {"D4R_PREFER_ACCURACY": "0"}).stdout)
|
||||
result = self.config("[Kernels]\nPreferAccuracy=perhaps\n", expected=2)
|
||||
self.assertIn("PreferAccuracy must be true or false", result.stderr)
|
||||
|
||||
def test_shipped_configs_default_off(self):
|
||||
for file in ("config/d4r.ini.default", "packaging/d4r.ini"):
|
||||
self.assertRegex((ROOT / file).read_text(), r"(?m)^PreferAccuracy\s*=\s*false$")
|
||||
|
||||
def test_builder_refuses_to_certify_mixed_fast_binaries(self):
|
||||
compiler = self.root / "rocm/lib/llvm/bin/clang++"
|
||||
compiler.parent.mkdir(parents=True)
|
||||
compiler.write_text("#!/bin/sh\nexit 99\n")
|
||||
compiler.chmod(0o755)
|
||||
output = self.root / "mixed"
|
||||
self.native(output, manifest=False)
|
||||
env = dict(os.environ, D4R_PREFER_ACCURACY="1", D4R_ROCM_DIR=str(self.root / "rocm"))
|
||||
for marker in (None, "0\n"):
|
||||
if marker is not None:
|
||||
(output / "d4r-accuracy.txt").write_text(marker)
|
||||
result = subprocess.run(["bash", str(ROOT / "kernels/build.sh"), "k", str(output)],
|
||||
env=env, text=True, capture_output=True)
|
||||
self.assertEqual(result.returncode, 2)
|
||||
self.assertIn("accuracy kernels need an empty output directory", result.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user