Skip to content

Commit 85b9834

Browse files
authored
Resolve compiler math libraries before native preparation (#88)
Select the CUDA math library required by compiled-forward eager precision before constructing recorded preparation sessions or entering standalone operator preparation. Native program discovery and materialization then use the same compiler options across serial and overlapping graph catalogs. Inductor initializes toolkit libdevice when Flare's emulate_precision_casts option first compiles a forward. Previously, b12x could memoize discovery with Triton's bundled library first, then request another library's program key while runtime compilation was forbidden. The two library files differ in content; retaining their distinct identities is required. Implemented in shared preparation without changing numerical options, kernel selection, cache equivalence or compilation guards. Qualified with 80 CPU checks, including two library-selection regressions that fail on prerequisite a2c9278 and pass with this correction. The regressions prohibit CUDA initialization and perform no compilation. GPU serial-to-overlap preparation and native replay remain unqualified pending an assigned validation window. Design-Signed-Off-By: Codex (GPT-6); design-review=babb
1 parent 5a32e30 commit 85b9834

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

‎ignition/preparation/tuning.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@
2727
_REQUESTS_PER_JOB = 192
2828

2929

30+
def _prepare_compiler_toolchain():
31+
"""Resolve forward math libraries before native program identities are recorded."""
32+
from torch._inductor import config
33+
from torch._inductor.runtime.compile_tasks import _set_triton_libdevice_path
34+
35+
from .compilation import _OPTIONS
36+
37+
# Inductor selects the CUDA toolkit's libdevice for eager precision. Native
38+
# discovery and later materialization must see that same library identity.
39+
with config.patch(emulate_precision_casts=_OPTIONS["emulate_precision_casts"]):
40+
_set_triton_libdevice_path()
41+
42+
3043
def with_autotune_effort(prepare):
3144
"""Apply the preparation config's effort throughout bootstrap declarations."""
3245
@wraps(prepare)
@@ -65,6 +78,7 @@ def __init__(self, *, device, checkpoint: str, workload_schema: str,
6578
numerical_policy=numerical_policy)
6679
self.autotune_effort = AutotuneEffort(autotune_effort).value
6780
self.native_dense_activations = native_dense_activations
81+
_prepare_compiler_toolchain()
6882
with b12x_autotune_effort(self.autotune_effort):
6983
super().__init__(device=device, autotune=self.autotune_effort != "off", compile_workers=0,
7084
namespace=identity, race_budget=race_budget, prime=False,
@@ -476,6 +490,7 @@ def declare(session, requests, *, coordinator=None):
476490
if isinstance(session, RecordedPreparationSession):
477491
session.declare(requests, coordinator=coordinator)
478492
else:
493+
_prepare_compiler_toolchain()
479494
options = {} if coordinator is None else {"coordinator": coordinator}
480495
session.prepare(requests, **options)
481496

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Native discovery and compiled forwards share one CUDA math-library identity."""
2+
3+
import os
4+
from pathlib import Path
5+
import subprocess
6+
import sys
7+
8+
import pytest
9+
10+
import ignition
11+
12+
13+
@pytest.mark.parametrize("session_kind", ["recorded", "standalone"])
14+
def test_discovery_options_survive_inductor_precision_initialization(session_kind):
15+
# A subprocess preserves the unset-library startup condition independently
16+
# of other tests that have already initialized Inductor.
17+
source = r'''
18+
from pathlib import Path
19+
import sys
20+
from unittest.mock import patch
21+
22+
import torch
23+
assert not torch.cuda.is_initialized()
24+
def reject_cuda(*args, **kwargs):
25+
raise RuntimeError("this compiler-identity check must not initialize CUDA")
26+
torch.cuda._lazy_init = reject_cuda
27+
28+
from torch.utils.cpp_extension import CUDA_HOME
29+
if CUDA_HOME is None:
30+
raise SystemExit(77)
31+
toolkit_library = Path(CUDA_HOME) / "nvvm/libdevice/libdevice.10.bc"
32+
if not toolkit_library.is_file():
33+
raise SystemExit(77)
34+
35+
from triton.backends.nvidia.compiler import CUDAOptions
36+
from torch._inductor import config
37+
from torch._inductor.runtime.compile_tasks import _set_triton_libdevice_path
38+
from b12x.preparation import PreparationSession
39+
from ignition.preparation.compilation import _OPTIONS
40+
from ignition.preparation.tuning import RecordedPreparationSession, declare
41+
42+
observed = []
43+
if sys.argv[1] == "recorded":
44+
# Only the GPU-owning base constructor is replaced. Flare's constructor
45+
# and the real Inductor/Triton library selection remain under test.
46+
def base_initialize(self, **kwargs):
47+
observed.append(CUDAOptions())
48+
with patch.object(PreparationSession, "__init__", base_initialize):
49+
RecordedPreparationSession(device=0, checkpoint="compiler-library",
50+
workload_schema="compiler-library", numerical_policy="default",
51+
compile_workers=1)
52+
else:
53+
class Standalone:
54+
def prepare(self, requests):
55+
observed.append(CUDAOptions())
56+
declare(Standalone(), ())
57+
58+
before = observed[0]
59+
with config.patch(emulate_precision_casts=_OPTIONS["emulate_precision_casts"]):
60+
_set_triton_libdevice_path()
61+
after = CUDAOptions()
62+
assert before.extern_libs == after.extern_libs, (
63+
"native discovery", before.extern_libs, "compiled forward", after.extern_libs)
64+
assert Path(dict(before.extern_libs)["libdevice"]) == toolkit_library, (
65+
before.extern_libs, toolkit_library)
66+
assert before.hash() == after.hash(), (before.hash(), after.hash())
67+
assert not torch.cuda.is_initialized()
68+
'''
69+
environment = dict(os.environ, CUDA_VISIBLE_DEVICES="")
70+
environment.pop("TRITON_LIBDEVICE_PATH", None)
71+
result = subprocess.run([sys.executable, "-c", source, session_kind],
72+
cwd=Path(ignition.__file__).resolve().parents[1], env=environment,
73+
capture_output=True, text=True)
74+
if result.returncode == 77:
75+
pytest.skip("requires the CUDA toolkit's libdevice bitcode")
76+
assert result.returncode == 0, result.stdout + result.stderr

0 commit comments

Comments
 (0)