cuda: compiler_v2 module becomes compiler

The package already exposed it as CelerisLab.cuda.compiler; the module now
has that name and every tip caller, doc and current-tree test imports it
directly (no alias).

Historical-revision tooling is not edited: the Taylor-Green harness
(run_case.py, hash-pinned check_projected_pairs.py, assess receipts) only
runs against a135252, whose package has cuda/compiler_v2.py, and the J
campaign runners and dated docs describe past trees. Its two current-tree
tests now import that package from git (historical_package) instead of the
tip, and the kernel-root test first checks the accepted case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-26 19:15:50 +00:00
1 parent 18e8ef45f0
commit d318911221
21 files changed
+65 -28

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ it is; it adds no framework. Line references are to candidate 0f8fdbc3.
| Class | Contents | How it changes | Owner rule | | Class | Contents | How it changes | Owner rule |
|---|---|---|---| |---|---|---|---|
| 1. Module and its globals | Compile-time (visible to the compiler, fixed per module): `config.h` macros incl. `NX`/`NY`, `COLLISION_MODEL`, `BLOCK_ROOT_BC`, `WALL_*`. Runtime per-module globals (not visible to the compiler; written by host code): `__constant__` `d_params`, `d_w`, `d_cx`, `d_cy`, `d_block_channel`, `d_block_wall`; plus bound kernel handles | Globals are written once by the owner right after `load_module`. Uniform grid: `Simulation._recompile` (construction, body-topology sync) loads a new module and re-uploads; `update_runtime_params` rewrites `d_params` (omega, force, n_objects) between runs. Steppers: never rewritten after construction, so they are immutable for the instance's lifetime although they are runtime values. The same quantity can be a macro in one route and a global in another (dense slot root: `WALL_SLOT_WIDTH`/`WALL_NORMAL_VELOCITY` macros; blocked slot root: `d_block_wall`), which can change generated arithmetic. | Every owner loads its own module (`compiler_v2.load_module` = `module_from_file`, no cache). A loaded module is never shared between live owners: globals are per module, so sharing would share mutable `d_params`. | | 1. Module and its globals | Compile-time (visible to the compiler, fixed per module): `config.h` macros incl. `NX`/`NY`, `COLLISION_MODEL`, `BLOCK_ROOT_BC`, `WALL_*`. Runtime per-module globals (not visible to the compiler; written by host code): `__constant__` `d_params`, `d_w`, `d_cx`, `d_cy`, `d_block_channel`, `d_block_wall`; plus bound kernel handles | Globals are written once by the owner right after `load_module`. Uniform grid: `Simulation._recompile` (construction, body-topology sync) loads a new module and re-uploads; `update_runtime_params` rewrites `d_params` (omega, force, n_objects) between runs. Steppers: never rewritten after construction, so they are immutable for the instance's lifetime although they are runtime values. The same quantity can be a macro in one route and a global in another (dense slot root: `WALL_SLOT_WIDTH`/`WALL_NORMAL_VELOCITY` macros; blocked slot root: `d_block_wall`), which can change generated arithmetic. | Every owner loads its own module (`compiler.load_module` = `module_from_file`, no cache). A loaded module is never shared between live owners: globals are per module, so sharing would share mutable `d_params`. |
| 2. Geometry, layout, tables | flags, curved-link tables, block layouts and halo pairs, transfer (explode/coalesce) tables, block kinds | Immutable for the life of an instance. Uniform grid: rebuilt by body sync. `FixedPatchStepper`: a geometry change is a new instance (`remap_child`), committed only after a successful transfer. | No in-place table edits. | | 2. Geometry, layout, tables | flags, curved-link tables, block layouts and halo pairs, transfer (explode/coalesce) tables, block kinds | Immutable for the life of an instance. Uniform grid: rebuilt by body sync. `FixedPatchStepper`: a geometry change is a new instance (`remap_child`), committed only after a successful transfer. | No in-place table edits. |
| 3. Controls and dependent boundary columns | Jet amplitude -> per-link `surface_velocity`; body actions (uniform grid) | Between steps, without a table or module rebuild (`set_jet_amplitude`). | Host copy commits only after the device upload succeeded; a device error fails the instance. | | 3. Controls and dependent boundary columns | Jet amplitude -> per-link `surface_velocity`; body actions (uniform grid) | Between steps, without a table or module rebuild (`set_jet_amplitude`). | Host copy commits only after the device upload succeeded; a device error fails the instance. |
| 4. Per-step state | population double buffers and their parity, raw-exchange ledgers, observations | Device-only during `step(n)` / `run(n)`; buffer swaps are host-handle swaps. | Valid on the host only after the single wait at the end of the call. | | 4. Per-step state | population double buffers and their parity, raw-exchange ledgers, observations | Device-only during `step(n)` / `run(n)`; buffer swaps are host-handle swaps. | Valid on the host only after the single wait at the end of the call. |
+2 -2
View File
@@ -11,7 +11,7 @@ Responsibilities:
Design:: Design::
Packed ``obs`` layout matches ``generate_config(..., n_objects=count)`` and Packed ``obs`` layout matches ``generate_config(..., n_objects=count)`` and
``config_obs.h`` macros. Host sizing uses :func:`~CelerisLab.cuda.compiler_v2.obs_layout`. ``config_obs.h`` macros. Host sizing uses :func:`~CelerisLab.cuda.compiler.obs_layout`.
Pending edits are lightweight: only the "intent" (add / remove) is stored. Pending edits are lightweight: only the "intent" (add / remove) is stored.
All derived quantities (flags, compact lists, GPU buffers) are built at All derived quantities (flags, compact lists, GPU buffers) are built at
@@ -28,7 +28,7 @@ import pycuda.driver as cuda
from .objects import SimObject from .objects import SimObject
from .registry import BodyRegistry from .registry import BodyRegistry
from .preprocess.flag_overlay import merge_flag_masks, validate_cut_link_ownership from .preprocess.flag_overlay import merge_flag_masks, validate_cut_link_ownership
from ..cuda.compiler_v2 import obs_layout from ..cuda.compiler import obs_layout
from ..cuda.obs_layout import ObsLayout from ..cuda.obs_layout import ObsLayout
from ..lbm.descriptors import ( from ..lbm.descriptors import (
FLUID, SOLID, FLUID, SOLID,
+1 -1
View File
@@ -7,7 +7,7 @@ Two JSON files:
config_body.json – object list config_body.json – object list
LBMConfig / BodyConfig are plain dataclasses; they translate to LBMConfig / BodyConfig are plain dataclasses; they translate to
macro dicts consumed by `cuda/compiler_v2.py` for header generation. macro dicts consumed by `cuda/compiler.py` for header generation.
""" """
import json import json
+2 -2
View File
@@ -60,14 +60,14 @@ Python `config.py` 只负责读取和校验,不是配置位置。显式配置
**`lbm/kernels/config/*.h` 由编译器根据 `LBMConfig` 自动生成,请勿手改。** **`lbm/kernels/config/*.h` 由编译器根据 `LBMConfig` 自动生成,请勿手改。**
仓库中检入的 `config/*.h` 可能是历史版本。`compiler_v2.generate_config` 会复制 kernel 源码到独立临时构建目录,并在副本中生成配置;不会改写包内头文件或 PTX。返回目录须显式传给 `compile_kernel(build_dir=...)`,编译结果与配置摘要均保存在该目录。`Simulation` 负责目录清理;直接使用编译器的调用者须调用 `cleanup_build_dir()`。跳过生成配置直接编译仓库中的 `uniform.cu` 属不受支持用法。 仓库中检入的 `config/*.h` 可能是历史版本。`compiler.generate_config` 会复制 kernel 源码到独立临时构建目录,并在副本中生成配置;不会改写包内头文件或 PTX。返回目录须显式传给 `compile_kernel(build_dir=...)`,编译结果与配置摘要均保存在该目录。`Simulation` 负责目录清理;直接使用编译器的调用者须调用 `cleanup_build_dir()`。跳过生成配置直接编译仓库中的 `uniform.cu` 属不受支持用法。
``` ```
config_lbm.json config_lbm.json
↓ load_lbm_config() ↓ load_lbm_config()
config.py:LBMConfig (读取 + 校验) config.py:LBMConfig (读取 + 校验)
↓ to_macros() ↓ to_macros()
cuda/compiler_v2.py (独立构建目录中生成 config/*.h) cuda/compiler.py (独立构建目录中生成 config/*.h)
↓ ↓
config_grid.h → NX, NY, NZ, NT, LATTICE_MODEL; config_grid.h → NX, NY, NZ, NT, LATTICE_MODEL;
DIM / NQ 由 LATTICE_MODEL 推导写入(与 grid.lattice_model 一致,非 JSON 顶层字段) DIM / NQ 由 LATTICE_MODEL 推导写入(与 grid.lattice_model 一致,非 JSON 顶层字段)
+1 -1
View File
@@ -1,4 +1,4 @@
"""CUDA build helpers (compilation itself does not need a live context).""" """CUDA build helpers (compilation itself does not need a live context)."""
from . import compiler_v2 as compiler from . import compiler
__all__ = ["compiler"] __all__ = ["compiler"]
@@ -1,4 +1,4 @@
# CelerisLab/cuda/compiler_v2.py # CelerisLab/cuda/compiler.py
""" """
Kernel configuration, compilation, and module loading. Kernel configuration, compilation, and module loading.
+1 -1
View File
@@ -2,7 +2,7 @@
"""Packed ``obs`` buffer layout for force / torque / sensor telemetry. """Packed ``obs`` buffer layout for force / torque / sensor telemetry.
Usage:: Usage::
Host code (e.g. ``ObjectManager``) and ``compiler_v2.generate_config`` must use Host code (e.g. ``ObjectManager``) and ``compiler.generate_config`` must use
the same ``dim`` and ``n_objects`` so allocation sizes match device macros. the same ``dim`` and ``n_objects`` so allocation sizes match device macros.
Design:: Design::
+1 -1
View File
@@ -17,7 +17,7 @@ from threading import RLock
import numpy as np import numpy as np
import pycuda.driver as cuda import pycuda.driver as cuda
from ..cuda import compiler_v2 as compiler from ..cuda import compiler
from .blocks import (NQ, BlockLayout2D, blocked_link_tables, launch_curved_boundary, from .blocks import (NQ, BlockLayout2D, blocked_link_tables, launch_curved_boundary,
launch_halo_copy, level_config) launch_halo_copy, level_config)
from .descriptors import D2Q9_EX, D2Q9_EY, FLUID, SOLID from .descriptors import D2Q9_EX, D2Q9_EY, FLUID, SOLID
+1 -1
View File
@@ -14,7 +14,7 @@ from threading import RLock
import numpy as np import numpy as np
import pycuda.driver as cuda import pycuda.driver as cuda
from ..cuda import compiler_v2 as compiler from ..cuda import compiler
from .blocks import BlockLayout2D, launch_curved_boundary, launch_halo_copy, level_config from .blocks import BlockLayout2D, launch_curved_boundary, launch_halo_copy, level_config
from .channel import channel_masks, validate_channel_config, validate_channel_transfers from .channel import channel_masks, validate_channel_config, validate_channel_transfers
from ..body.jets import jet_link_velocity from ..body.jets import jet_link_velocity
+1 -1
View File
@@ -25,7 +25,7 @@ import pycuda.driver as cuda
from .config import LBMConfig, BodyConfig, load_lbm_config, load_body_config from .config import LBMConfig, BodyConfig, load_lbm_config, load_body_config
from .cuda.context import CudaContext, context_bound from .cuda.context import CudaContext, context_bound
from .cuda import compiler_v2 as compiler from .cuda import compiler
from .lbm.field import LBMField from .lbm.field import LBMField
from .lbm.stepper import LBMStepper from .lbm.stepper import LBMStepper
from .body.objects import SimObject from .body.objects import SimObject
@@ -6,14 +6,14 @@ import pycuda.driver as cuda
import pytest import pytest
import CelerisLab import CelerisLab
from CelerisLab.cuda import compiler_v2 from CelerisLab.cuda import compiler
from ._cases import make_sim from ._cases import make_sim
def test_source_provenance(): def test_source_provenance():
root = Path(__file__).resolve().parents[2] / "src/CelerisLab" root = Path(__file__).resolve().parents[2] / "src/CelerisLab"
assert Path(CelerisLab.__file__).resolve().parent == root assert Path(CelerisLab.__file__).resolve().parent == root
assert Path(compiler_v2.kernel_path("uniform.cu")).resolve() == root / "lbm/kernels/uniform.cu" assert Path(compiler.kernel_path("uniform.cu")).resolve() == root / "lbm/kernels/uniform.cu"
def test_two_contexts_interleaved_and_non_lifo_close(): def test_two_contexts_interleaved_and_non_lifo_close():
+1 -1
View File
@@ -9,7 +9,7 @@ import pytest
import CelerisLab import CelerisLab
from CelerisLab.config import LBMConfig, load_lbm_config from CelerisLab.config import LBMConfig, load_lbm_config
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.common.checkpoint import save_checkpoint, load_checkpoint from CelerisLab.common.checkpoint import save_checkpoint, load_checkpoint
from .test_numerical_operators import compile_run from .test_numerical_operators import compile_run
from .test_state_regressions import device, make_field, manager from .test_state_regressions import device, make_field, manager
@@ -21,7 +21,7 @@ import pycuda.driver as cuda
from CelerisLab.body.geometry.circle import CircleGeometry from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject from CelerisLab.body.objects import SimObject
from CelerisLab.config import LBMConfig from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.lbm import block_stepper as implementation from CelerisLab.lbm import block_stepper as implementation
from CelerisLab.lbm.blocks import NO_DONOR, BlockLayout2D from CelerisLab.lbm.blocks import NO_DONOR, BlockLayout2D
from CelerisLab.lbm.block_stepper import PeriodicBlockStepper from CelerisLab.lbm.block_stepper import PeriodicBlockStepper
@@ -11,7 +11,7 @@ import numpy as np
import pycuda.driver as cuda import pycuda.driver as cuda
from CelerisLab.config import LBMConfig from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.cuda.context import CudaContext from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.blocks import BlockLayout2D from CelerisLab.lbm.blocks import BlockLayout2D
from CelerisLab.lbm.descriptors import FLUID, SOLID, BC_WALL, BC_INLET, BC_OUTLET from CelerisLab.lbm.descriptors import FLUID, SOLID, BC_WALL, BC_INLET, BC_OUTLET
@@ -18,7 +18,7 @@ import CelerisLab
from CelerisLab.body.geometry.circle import CircleGeometry from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject from CelerisLab.body.objects import SimObject
from CelerisLab.config import LBMConfig from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.cuda.context import CudaContext from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm import refinement_stepper as implementation from CelerisLab.lbm import refinement_stepper as implementation
from CelerisLab.lbm.descriptors import FLUID, SOLID from CelerisLab.lbm.descriptors import FLUID, SOLID
@@ -13,7 +13,7 @@ from unittest.mock import Mock, patch
import numpy as np import numpy as np
import pycuda.driver as cuda import pycuda.driver as cuda
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.lbm import refinement_stepper from CelerisLab.lbm import refinement_stepper
from CelerisLab.lbm.blocks import BlockLayout2D from CelerisLab.lbm.blocks import BlockLayout2D
from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY
@@ -15,7 +15,7 @@ import pycuda.driver as cuda
from CelerisLab.body.geometry.circle import CircleGeometry from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject, SurfaceActuation from CelerisLab.body.objects import SimObject, SurfaceActuation
from CelerisLab.config import LBMConfig from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.lbm import curved_links from CelerisLab.lbm import curved_links
from CelerisLab.lbm.blocks import NO_DONOR, BlockLayout2D, blocked_link_tables from CelerisLab.lbm.blocks import NO_DONOR, BlockLayout2D, blocked_link_tables
from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY
@@ -20,7 +20,7 @@ import pycuda.driver as cuda
import CelerisLab import CelerisLab
from CelerisLab.config import LBMConfig from CelerisLab.config import LBMConfig
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.cuda.context import CudaContext from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper, PeriodicPatchStepper from CelerisLab.lbm.refinement_stepper import FixedPatchStepper, PeriodicPatchStepper
@@ -16,7 +16,7 @@ from unittest.mock import Mock, patch
import numpy as np import numpy as np
import pycuda.driver as cuda import pycuda.driver as cuda
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
from CelerisLab.lbm.descriptors import SOLID from CelerisLab.lbm.descriptors import SOLID
from CelerisLab.lbm.refinement import ACTIVE, FixedPatch2D, prepare_fine_boundary from CelerisLab.lbm.refinement import ACTIVE, FixedPatch2D, prepare_fine_boundary
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
@@ -52,7 +52,7 @@ def child_jet(speed=.002):
def mocked_child(): def mocked_child():
from CelerisLab.cuda import compiler_v2 as compiler from CelerisLab.cuda import compiler
context = Mock(activate=nullcontext, sm_arch="sm_70") context = Mock(activate=nullcontext, sm_arch="sm_70")
module = Mock(get_function=Mock(side_effect=lambda name: Mock(name=name))) module = Mock(get_function=Mock(side_effect=lambda name: Mock(name=name)))
module.get_global.return_value = (Mock(), 20) module.get_global.return_value = (Mock(), 20)
@@ -1,6 +1,6 @@
"""Host geometry, receipt-corruption tests and mocked scheduling; no CUDA/flow.""" """Host geometry, receipt-corruption tests and mocked scheduling; no CUDA/flow."""
from contextlib import nullcontext, redirect_stdout from contextlib import contextmanager, nullcontext, redirect_stdout
from copy import deepcopy from copy import deepcopy
from dataclasses import asdict, replace from dataclasses import asdict, replace
import hashlib import hashlib
@@ -24,6 +24,37 @@ from oracle import LIMITS, TIMES, U, rectangles
REPO = Path(__file__).resolve().parents[3] REPO = Path(__file__).resolve().parents[3]
OLD_REVISION = "519473a61c7b319183aa54e55b9f097499dde0bf" OLD_REVISION = "519473a61c7b319183aa54e55b9f097499dde0bf"
MOCK_REVISION = "f" * 40 MOCK_REVISION = "f" * 40
@contextmanager
def historical_package():
"""Import CelerisLab from NUMERICAL_REVISION, the only tree run_case accepts.
The harness and its pinned build-capture helper are tooling for that revision
(cuda/compiler_v2.py); the current package is restored afterwards.
"""
import tarfile
archive = subprocess.run(["git", "-C", str(REPO), "archive", "--format=tar",
NUMERICAL_REVISION, "src/CelerisLab"],
capture_output=True, check=True).stdout
before = set(sys.modules)
saved = {k: v for k, v in sys.modules.items() if k == "CelerisLab" or k.startswith("CelerisLab.")}
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
with tarfile.open(fileobj=io.BytesIO(archive)) as tar:
tar.extractall(root)
for name in saved:
del sys.modules[name]
sys.path.insert(0, str(root / "src"))
try:
yield root
finally:
sys.path.remove(str(root / "src"))
for name in set(sys.modules) - before | set(saved): # nothing keeps the old tree
sys.modules.pop(name, None)
sys.modules.update(saved)
RUNTIME = dict(device=dict(name="host mock", pci_bus_id="mock", capability=[7, 0], RUNTIME = dict(device=dict(name="host mock", pci_bus_id="mock", capability=[7, 0],
driver=12040, runtime=[12, 4, 0]), nvcc_path="/mock/nvcc", driver=12040, runtime=[12, 4, 0]), nvcc_path="/mock/nvcc",
nvcc_version="mock nvcc", python="mock Python", numpy=np.__version__, pycuda="mock") nvcc_version="mock nvcc", python="mock Python", numpy=np.__version__, pycuda="mock")
@@ -125,6 +156,10 @@ class ProjectedPairsTests(unittest.TestCase):
frozen[name]) frozen[name])
def test_actual_build_capture_rejects_tampered_ptx_and_sidecar(self): def test_actual_build_capture_rejects_tampered_ptx_and_sidecar(self):
with historical_package():
self._check_build_capture()
def _check_build_capture(self):
from CelerisLab.cuda import compiler_v2 from CelerisLab.cuda import compiler_v2
from tests.validation.multigrid.check_projected_pairs import capture_builds from tests.validation.multigrid.check_projected_pairs import capture_builds
@@ -346,10 +381,12 @@ class ProjectedPairsTests(unittest.TestCase):
self.assertFalse(output.exists()) self.assertFalse(output.exists())
def test_runtime_rejects_installed_kernel_tree(self): def test_runtime_rejects_installed_kernel_tree(self):
from CelerisLab.cuda import compiler_v2 with historical_package() as repo:
with patch.object(compiler_v2, "_KERNEL_DIR", "/other/CelerisLab/lbm/kernels"): from CelerisLab.cuda import compiler_v2
with self.assertRaisesRegex(RuntimeError, "CUDA source/include root"): self.assertEqual(run_case.runtime_source(repo)["checkout"], str(repo))
run_case.runtime_source(REPO) with patch.object(compiler_v2, "_KERNEL_DIR", "/other/CelerisLab/lbm/kernels"):
with self.assertRaisesRegex(RuntimeError, "CUDA source/include root"):
run_case.runtime_source(repo)
def test_existing_output_is_never_overwritten(self): def test_existing_output_is_never_overwritten(self):
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp: