__init__.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. """b12x — consumer-Blackwell (SM120/SM121) kernels.
  2. CuTe-DSL kernels for NVFP4/MXFP4/MXFP8 GEMM, fused MoE, attention (paged,
  3. dense/sparse/compressed MLA, NSA indexing), quantization, mHC residual, and PCIe
  4. collectives, ported from the b12x project. One grammar everywhere:
  5. - ops live at ``b12x.<group>.<op>`` and declare themselves via ``META``;
  6. - planned ops share the lifecycle ``Caps -> plan() -> bind() ->
  7. run*()`` (``plan`` may allocate; ``bind`` builds views only and never
  8. allocates; ``run*`` is CUDA-graph-capture safe);
  9. - one-shot ops are plain functions; comm collectives are classes.
  10. Serving controls (`freeze_kernel_resolution` & friends) live here at the
  11. arch root because they guard the shared compiler: warm every kernel shape,
  12. then freeze so a cache miss raises instead of compiling inside a live
  13. request or graph capture.
  14. Importing this module is cheap and side-effect free; kernels, cutlass, and
  15. torch custom ops load on first op use.
  16. """
  17. from __future__ import annotations
  18. import importlib
  19. import sys
  20. from typing import Any
  21. from ._lib.meta import OpMeta
  22. from ._lib.runtime_control import (
  23. KernelResolutionFrozenError,
  24. compilation_frozen,
  25. freeze_compilation,
  26. freeze_kernel_resolution,
  27. kernel_resolution_frozen,
  28. unfreeze_compilation,
  29. unfreeze_kernel_resolution,
  30. )
  31. # Static logical-op registry, kept in lockstep with public op directories and
  32. # the explicit private-module overrides below by tests/test_registry.py.
  33. _OPS: tuple[str, ...] = (
  34. "attention.paged",
  35. "attention.dense_mla",
  36. "attention.sparse_mla",
  37. "attention.compressed_mla",
  38. "attention.nsa_indexer",
  39. "attention.varlen",
  40. "comm.pcie",
  41. "comm.roce",
  42. "gemm.blockscaled",
  43. "gemm.block_fp8_linear",
  44. "gemm.bmm",
  45. "gemm.mxfp8_linear",
  46. "gemm.tensor_fp8_linear",
  47. "gemm.mla_query_projection",
  48. "gemm.trellis_linear",
  49. "gemm.wo_projection",
  50. "moe.fused_moe",
  51. "moe.ep_moe",
  52. "norm.mhc",
  53. "quantization.mxfp8",
  54. "quantization.nvfp4",
  55. )
  56. # A group-level function cannot share its name with an imported child module.
  57. # These registry entries keep their public qualname while their metadata and
  58. # implementation live under a private package.
  59. _OP_MODULE_OVERRIDES: dict[str, str] = {
  60. "gemm.bmm": "gemm._bmm",
  61. }
  62. _CACHE_CLEAR_OVERRIDES: dict[str, str] = {
  63. "gemm.bmm": "clear_bmm_caches",
  64. }
  65. _GROUPS = ("attention", "comm", "gemm", "moe", "norm", "quantization")
  66. _LAZY_ROOT_ATTRS: dict[str, tuple[str, str]] = {
  67. # public name -> (module, attribute)
  68. "ScratchBufferSpec": ("._lib.scratch", "ScratchBufferSpec"),
  69. }
  70. def _op_module_path(qualname: str) -> str:
  71. return _OP_MODULE_OVERRIDES.get(qualname, qualname)
  72. def list_ops() -> tuple[OpMeta, ...]:
  73. """Import every op's (cheap) ``__init__`` and return their ``META``s."""
  74. return tuple(
  75. importlib.import_module(f".{_op_module_path(op_path)}", __name__).META
  76. for op_path in _OPS
  77. )
  78. def find_op(qualname: str) -> OpMeta:
  79. """Look up one op's ``META`` by ``"<group>.<op>"`` qualname."""
  80. if qualname not in _OPS:
  81. raise KeyError(
  82. f"unknown experimental b12x op {qualname!r}; known ops: {sorted(_OPS)}"
  83. )
  84. return importlib.import_module(f".{_op_module_path(qualname)}", __name__).META
  85. def clear_all_caches() -> None:
  86. """Clear caches of every op already imported; never forces imports."""
  87. for op_path in _OPS:
  88. module_path = _op_module_path(op_path)
  89. api = sys.modules.get(f"{__name__}.{module_path}.api")
  90. clear_name = _CACHE_CLEAR_OVERRIDES.get(op_path, "clear_caches")
  91. clear = getattr(api, clear_name, None) if api is not None else None
  92. if clear is not None:
  93. clear()
  94. compiler = sys.modules.get(f"{__name__}._lib.compiler")
  95. if compiler is not None:
  96. compiler.clear_compile_cache()
  97. def __getattr__(name: str) -> Any:
  98. if name in _GROUPS:
  99. module = importlib.import_module(f".{name}", __name__)
  100. globals()[name] = module
  101. return module
  102. if name in _LAZY_ROOT_ATTRS:
  103. module_name, attr = _LAZY_ROOT_ATTRS[name]
  104. value = getattr(importlib.import_module(module_name, __name__), attr)
  105. globals()[name] = value
  106. return value
  107. raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
  108. def __dir__() -> list[str]:
  109. return sorted([*__all__, *_GROUPS])
  110. __all__ = [
  111. "KernelResolutionFrozenError",
  112. "OpMeta",
  113. "ScratchBufferSpec",
  114. "clear_all_caches",
  115. "compilation_frozen",
  116. "find_op",
  117. "freeze_compilation",
  118. "freeze_kernel_resolution",
  119. "kernel_resolution_frozen",
  120. "list_ops",
  121. "unfreeze_compilation",
  122. "unfreeze_kernel_resolution",
  123. ]