Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions src/paddlefleet/cudnn_ops/attn/csa_sparse_attn_bwd_cudnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,130 @@ def _require_cudnn_frontend():
raise ImportError(CUDNN_FRONTEND_HINT)


def _patch_paddle_memory_format():
"""Patch paddle with torch.memory_format sentinel attributes for H-Card.

The cudnn package's api_base.TensorDesc.is_contiguous() uses
torch.contiguous_format / preserve_format / channels_last / channels_last_3d
for memory layout checks. When Paddle's torch-proxy intercepts `import torch`,
these attributes are missing. We inject them as unique sentinel objects so that
identity/equality checks in cudnn work correctly.
"""
import paddle

class _MemoryFormat:
"""Minimal stand-in for torch.memory_format enum values."""

def __init__(self, name):
self._name = name

def __repr__(self):
return f"paddle.{self._name}"

def __hash__(self):
return hash(self._name)

def __eq__(self, other):
return self is other

for name in (
"contiguous_format",
"preserve_format",
"channels_last",
"channels_last_3d",
):
if not hasattr(paddle, name):
setattr(paddle, name, _MemoryFormat(name))

# Also need paddle.memory_format type for type annotations
if not hasattr(paddle, "memory_format"):
paddle.memory_format = type(_MemoryFormat("contiguous_format"))


_patch_paddle_memory_format()


def _patch_cutlass_nvgpu():
"""Patch cutlass.cute.nvgpu to expose OperandMajorMode at top level for H-Card.

The cudnn SM90 backward kernel (dsa_bwd_sm90.py) references
cute.nvgpu.OperandMajorMode, but in cutlass 4.4.x this symbol lives
under cute.nvgpu.warpgroup. Promote it so the kernel can find it.
"""
try:
from cutlass.cute import nvgpu

if not hasattr(nvgpu, "OperandMajorMode"):
from cutlass.cute.nvgpu.warpgroup import OperandMajorMode

nvgpu.OperandMajorMode = OperandMajorMode
except (ImportError, AttributeError):
pass


_patch_cutlass_nvgpu()


def _patch_paddle_nvtx_range():
"""Patch paddle nvtx classes with a ``range`` context-manager for H-Card.

The cudnn SM90 backward kernel uses ``torch.cuda.nvtx.range(...)`` as a
context manager. When Paddle's torch-proxy is active, ``torch.cuda.nvtx``
resolves to ``paddle.cuda.nvtx`` (NOT paddle.device.nvtx). Both classes
only expose ``range_push`` / ``range_pop``. We inject a compatible ``range``
into both to be safe.
"""
from contextlib import contextmanager

import paddle

def _inject_range(nvtx_cls):
if nvtx_cls is None or hasattr(nvtx_cls, "range"):
return

@contextmanager
def _nvtx_range(msg: str, *args, **kwargs):
nvtx_cls.range_push(msg.format(*args, **kwargs))
try:
yield
finally:
nvtx_cls.range_pop()

nvtx_cls.range = staticmethod(_nvtx_range)

_inject_range(getattr(paddle.device, "nvtx", None))
_inject_range(getattr(paddle.cuda, "nvtx", None))


_patch_paddle_nvtx_range()


def _patch_paddle_stream_cuda_stream():
"""Give paddle.device.Stream a torch-like ``cuda_stream`` property for H-Card.

cudnn's resolve_stream() defaults to torch.cuda.current_stream().cuda_stream.
Under Paddle's torch-proxy that returns a paddle Stream, which exposes the
raw stream as stream_base.cuda_stream instead. Bridging the attribute makes
resolve_stream() pick up Paddle's current stream on both SM90 and SM100.
"""
import paddle
from paddle.base import core

S = paddle.device.Stream
if not hasattr(S, "cuda_stream"):

def _cuda_stream(self):
assert isinstance(self.stream_base, core.CUDAStream), (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 建议 这里用 assert 做运行期 stream 类型校验,python -O 下会被移除。

cuda_stream 是导入模块时注入到 paddle.device.Stream 的兼容属性,后续 cuDNN resolve_stream() 会按普通属性访问它;如果遇到非 CUDA stream,当前 guard 在优化模式下不会执行,代码会继续读 self.stream_base.cuda_stream,错误类型和信息都不再可控。测试里也把 AssertionError 固化为期望行为。

建议修复方式:改成显式异常,并同步测试期望,例如:

if not isinstance(self.stream_base, core.CUDAStream):
    raise RuntimeError("cuda_stream is only available for CUDA streams")

"cuda_stream is only available for CUDA streams"
)
return self.stream_base.cuda_stream

S.cuda_stream = property(_cuda_stream)


_patch_paddle_stream_cuda_stream()


def csa_sparse_attn_bwd_cudnn(
q, # (total_sq, H, D) bf16
kv, # (total_skv, D) bf16
Expand Down
Loading
Loading