Skip to content

[All] Refactor fused attention APIs with cuDNN-frontend support checks and opaque config/params handles - #2964

Open
cyanguwa wants to merge 151 commits into
NVIDIA:mainfrom
cyanguwa:fe_check_support
Open

[All] Refactor fused attention APIs with cuDNN-frontend support checks and opaque config/params handles#2964
cyanguwa wants to merge 151 commits into
NVIDIA:mainfrom
cyanguwa:fe_check_support

Conversation

@cyanguwa

@cyanguwa cyanguwa commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Description

TE currently hand-maintains the fused-attention backend-selection logic in nvte_get_fused_attn_backend, duplicating cuDNN's support rules. This list drifts out of sync as cuDNN evolves, and the support check can disagree with what actually runs.

This PR replaces that logic with cuDNN-frontend's production-grade support checks. The new nvte_get_fused_attn_backend_v2 builds the same graph cuDNN executes at runtime, so the probe and execution can no longer diverge. It caches the graph on success and returns a diagnostic message on failure, giving users actionable guidance (e.g. adjust the config, GPU architecture, or cuDNN version).

This PR also reworks nvte_fused_attn_fwd / nvte_fused_attn_bwd into nvte_fused_attn_fwd_v2 / nvte_fused_attn_bwd_v2, which take opaque, attribute-based config/params handles instead of long flat argument lists — improving TE's API and ABI stability.

Legacy APIs are retained as deprecated shims that route through the v2 APIs, so existing callers keep working.

Type of change

  • Documentation change (change only to the documentation, either a fix or a new content)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Infra/Build change
  • Code refactoring

Changes

API rework (opaque config/params + v2 entry points)

  • Opaque config/params handles (common/fused_attn/config_and_params.{h,cpp}, common/include/transformer_engine/fused_attn.h): new NVTEFusedAttnConfig / NVTEFusedAttnFwdParams / NVTEFusedAttnBwdParams with create/destroy/get/set attribute accessors, for better API/ABI stability. The cache key, probe, and execution now all originate from one place via make_config / derive / make_cache_key.
  • v2 APIs (common/fused_attn/fused_attn*.{cpp,cu}): nvte_get_fused_attn_backend_v2, nvte_fused_attn_fwd_v2, and nvte_fused_attn_bwd_v2. The F16 and FP8 supported_verdict_* probes copy the config, set direction, derive(), and attempt a null-pointer graph build via check_support — i.e. the same graph cuDNN builds at runtime, so probe and execution can't diverge.
  • Deprecated shims: legacy nvte_get_fused_attn_backend / nvte_fused_attn_fwd / nvte_fused_attn_bwd are retained, routed through the v2 APIs.
  • Bindings updated to v2: PyTorch (csrc/extensions/attention.cpp) and JAX (jax/csrc/extensions/attention.cpp).

Correctness & backend selection

  • Process-wide graph cache: cache is now process-wide (was thread-local) and guarded by a mutex, so a compiled graph is reused across threads instead of rebuilt per thread (still thread-safe).
  • Bias-shape handling fix: applied consistently across common, PyTorch, and JAX.
  • Per-step CP config checks: cp_per_step_configs probes each context-parallel step instead of only the global, non-CP config.
  • log2(0) guard: avoids UB when casting -inf to size_t in get_max_batch_size / get_max_tokens.

Diagnostics

  • NVTE_DEBUG / NVTE_DEBUG_LEVEL for JAX (parity with PyTorch): level 1 reports the selected backend; level 2 adds a diagnostic message explaining why fused attention was rejected.
  • Fused attention graph cache debug NVTE_FUSED_ATTN_CACHE_DEBUG=<level>[:<ranks>]: opt-in instrumentation that reports cuDNN graph build-vs-execution counts and per-stage cudnn-frontend build timings, so cache hit/miss/build/exec behaviors and graph build time can be inspected. Off by default; [:<ranks>] specifies select ranks for diagnostics; available for both PyTorch and Jax.

Cleanup / removals

  • Removed NVTE_FUSED_ATTN_BACKEND — the two remaining backends (F16, FP8) are mutually exclusive now that max512 is gone.
  • Removed dead Q_ID/.../MASK_VAL_ID macros (used only by the max512 backend).
  • Removed dead cudnn_frontend::xxx utility functions (used only by fp8_impl_v0 and max512).
  • Unified include-guard names across fused_attn/ headers.

Tests

  • Enabled previously skipped tests: padding + post_scale_bias in both PyTorch and Jax, D256 bprop in PyTorch, and SWA + dropout/post_scale_bias in Jax.
  • Curated the L0 sweeps to keep CI time in check: deduplicated PyTorch tests, and tiered the newly enabled JAX tests across L0/L1/L2.
  • Added test_fused_attn_graph_cache to test graph cache's behavior with NVTE_FUSED_ATTN_CACHE_DEBUG=2 on, and test_fused_attn_backend_message to test the surfacing of TE-specific or cuDNN-related error messages to users.

Checklist:

  • I have read and followed the contributing guidelines
  • The functionality is complete
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

cyanguwa and others added 4 commits May 5, 2026 18:55
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa cyanguwa changed the title [Common] Refactor nvte_get_fused_attn_backend with cudnn-frontend calls [All] Refactor nvte_get_fused_attn_backend with cudnn-frontend calls May 8, 2026
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa
cyanguwa marked this pull request as ready for review May 8, 2026 00:10
@greptile-apps

greptile-apps Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR refactors fused-attention backend selection and execution around opaque configuration/parameter handles and cuDNN-frontend support checks.

  • Adds v2 native APIs and compatibility shims for legacy callers.
  • Unifies support probing, graph-cache keys, and runtime configuration derivation.
  • Updates PyTorch and JAX bindings, diagnostics, context-parallel checks, and test coverage.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains established at the current head.

No blocking failure remains.

Important Files Changed

Filename Overview
transformer_engine/common/fused_attn/config_and_params.cpp Implements opaque attribute access, derives normalized fused-attention configurations, and now carries device-local cache identity.
transformer_engine/common/fused_attn/fused_attn.cpp Replaces hand-maintained backend selection with v2 cuDNN-frontend probes and routes legacy and framework execution through the new configuration model.
transformer_engine/common/fused_attn/graph_cache.h Centralizes process-wide, mutex-protected graph lookup and support checking.
transformer_engine/jax/csrc/extensions/attention.cpp Updates JAX fused-attention execution and THD probing to populate the v2 native parameter contract.
transformer_engine/pytorch/csrc/extensions/attention.cpp Migrates PyTorch fused-attention bindings to typed opaque parameter wrappers.

Sequence Diagram

sequenceDiagram
    participant Framework as PyTorch/JAX
    participant Config as Opaque config/params
    participant Selector as Backend selector
    participant Cache as Process graph cache
    participant cuDNN as cuDNN frontend
    Framework->>Config: Populate request attributes
    Config->>Selector: Derive normalized configuration
    Selector->>Cache: Lookup device-specific graph key
    alt cached supported graph
        Cache-->>Selector: Reuse graph
    else cache miss
        Selector->>cuDNN: Build and check graph support
        cuDNN-->>Cache: Cache supported graph
    end
    Selector-->>Framework: Backend and diagnostic
    Framework->>Cache: Execute matching graph
Loading

Reviews (65): Last reviewed commit: "minor tweaks to common" | Re-trigger Greptile

Comment thread transformer_engine/common/fused_attn/fused_attn_fp8.cu Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn_fp8.cu Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp
Comment thread transformer_engine/common/include/transformer_engine/fused_attn.h Outdated
cyanguwa and others added 2 commits May 7, 2026 17:22
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp Outdated
cyanguwa and others added 3 commits May 7, 2026 18:30
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa

cyanguwa commented May 8, 2026

Copy link
Copy Markdown
Collaborator Author

/te-ci L1

Comment thread transformer_engine/common/fused_attn/fused_attn_f16_arbitrary_seqlen.cu Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn_f16_arbitrary_seqlen.cu Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Comment thread transformer_engine/common/fused_attn/fused_attn_f16_arbitrary_seqlen.cu Outdated
Comment thread transformer_engine/common/fused_attn/fused_attn_f16_arbitrary_seqlen.cu Outdated
cyanguwa and others added 3 commits May 7, 2026 22:28
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp Outdated
Comment thread transformer_engine/jax/cpp_extensions/attention.py Outdated
cyanguwa and others added 2 commits May 8, 2026 12:19
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Comment thread transformer_engine/common/fused_attn/fused_attn.cpp Outdated
@cyanguwa

Copy link
Copy Markdown
Collaborator Author

/te-ci L0 L1 L2 L3

graph_cache_debug::record_hit_miss(backend, pass, LookupResult::Miss, key);

auto entry = std::make_shared<CacheEntry<GraphAndTensors>>(build());
graph_cache_debug::record_create_graph(backend, pass);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think recording unconditionally can cause a. mismatch right ?
record_cache_graph() runs before we know whether a given thread won insertion. With concurrent same-key misses, both builders increment CACHE_GRAPH, although only one entry is inserted and the losing graph is discarded.
IIUC CACHE_GRAPH is supposed to be number of graphs cached so in the above case it might increase that number by 1 incorrectly (this is relevant for what is reported in logs and does not affect the feature code)

Could we inspect insert(...).second under the mutex, then call record_cache_graph() outside the lock only for the winner? CREATE_GRAPH can still count both builds because it is creating those 2 graphs but only 1 is being cached.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed as you suggested: the insert result is captured under the mutex, the lock is
released, and record_cache_graph() fires outside the lock only when
result.second is true. CREATE_GRAPH still counts every build, since multiple graphs
really were built.


// Per-thread counters, so the summary can break every column down by thread and backend.
struct ThreadCounters {
unsigned tid = 0;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The per thread structure has only one device, which should be okay for most cases, but I'm wondering if we have:
GPU0: 10 fwd events
GPU1: 4 fwd events

Summary might say: tid=2 dev=1 hit=14 which would imply that all events belong to GPU1 when then came from GPU 0

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. ThreadCounters now carries a multi_device flag set by a note_device() helper,
and the summary prints dev=mixed instead of naming a device when a thread's events
span more than one. The per-thread block are kept un-split by device, and the accurate per-device attribution can be found out by using level 2 diagnostics: the event lines do carry the live device ID.

Comment on lines +130 to +139
const char *fallback = nullptr;
try {
get_graph<kBackend, kPass, kCreateGraphFn>(cfg, handle);
return "";
} catch (const std::exception &e) {
if (e.what()[0] != '\0') return e.what();
fallback = "rejected without a reason.";
} catch (...) {
fallback = "unknown failure.";
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems to treat every thrown exception as a support rejected which is okay for when cuDNN is unsupported but it would also potentially incorrectly report other failures like RT error, bad_alloc or some cuda error as No backend.
Would be good if we could classify this ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. Now query_support() throws a dedicated
detail::UnsupportedByCudnn, support_verdict() catches only that, and the catch (...)
is gone, so a non-empty return means cuDNN said no and anything genuinely broken surfaces
as an error.

Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
…cord cache_graph after insert on winner thread

Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa

Copy link
Copy Markdown
Collaborator Author

/te-ci L0 L1 L2 L3

Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa

Copy link
Copy Markdown
Collaborator Author

/te-ci L0 L1 L2 L3

@cyanguwa cyanguwa added 2.20 and removed 2.19 labels Aug 28, 2026
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
@cyanguwa

cyanguwa commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

/te-ci L0 L1 L2 L3

@cyanguwa
cyanguwa requested review from KshitijLakhani and removed request for KshitijLakhani, ksivaman and ptrendx September 2, 2026 21:49
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Signed-off-by: Charlene Yang <8636796+cyanguwa@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants