Update QoLA/AITER #599
Conversation
| # commit QoLA will actually check out and build, not whatever happens to be | ||
| # the submodule's current HEAD at configure time. | ||
| set(__QOLA_MANIFEST "${CMAKE_CURRENT_LIST_DIR}/qola_manifest.toml") | ||
| set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${__QOLA_MANIFEST}") |
There was a problem hiding this comment.
AITER_SHA is not cached variable. Why is CMAKE_CONFIGURE_DEPENDS needed?
There was a problem hiding this comment.
I mainly have it so that direct cmake or ninja building will catch on manifest changes since I use it for incremental builds (and am thinking about including an incremental build option for TE's AITER FA backend). It's not strictly necessary, just a nice to have in such a workflow
There was a problem hiding this comment.
Will it also trigger re-executing of QoLA cli in the parent (ck_used_attn/ ) CMAkeLists.txt?
| return nullptr; | ||
| } | ||
| void* ptr = nullptr; | ||
| if(hipMallocAsync(&ptr, bytes, stream) != hipSuccess){ |
There was a problem hiding this comment.
Emm, if we let hip runtime to allocate and manage our buffers, this will create a series of issues. For example, if Pytorch or JAX users pre-allocate 97% of HBM, then our hipMallocAsync will return out of memory.
If what new aiter needs for fmha_args.workspace_alloc is a lambda, we can fake it to give jax/pytorch generated workspace buffer ptr?
| // callback thread, which holds runtime locks — calling any HIP API from it | ||
| // (including hipHostFree) deadlocks against concurrent main-thread HIP | ||
| // calls. Defer the free to ck_tile::pinned_host_releaser's worker thread. | ||
| fmha_args.pinned_host_alloc = [](size_t bytes) -> std::shared_ptr<void> { |
There was a problem hiding this comment.
Emm, why do they need host memory allocated? Is it for inference?
Again, can we fake the lambda to use pytorch/jax generated workspace?
VeeraRajasekhar
left a comment
There was a problem hiding this comment.
Verified that ROCm/rocm-libraries#6764 exists in the current pinned aiter commit.
| size_t head_dim_v, | ||
| int64_t window_size_left, | ||
| int64_t window_size_right, | ||
| bool is_training, bool cuda_graph) { |
There was a problem hiding this comment.
From my understanding, is_ck_backend_supported is the only consumer of the new graph-capture gate, but it's called without deterministic (TransformerEngine\transformer_engine\common\fused_attn_rocm\fused_attn.cpp line 320) even though nvte_get_fused_attn_backend has it in scope (TransformerEngine\transformer_engine\common\fused_attn_rocm\fused_attn.cpp line 282).
Since deterministic bwd forces the non-graph-safe CK v2 path, is_ck_bwd_graph_capture_safe cannot make the right call without it. See my other related comments above for what could be added to fix.
You should include here the bool deterministic as well
| is_v3_arch && | ||
| dropout == 0.f && | ||
| bias_type == NVTE_Bias_Type::NVTE_NO_BIAS && | ||
| max_seqlen_q >= 16; |
| // unaffected). Determinism also forces v2 but is invisible here, so it is handled | ||
| // on the framework side. | ||
| if(is_training && cuda_graph && | ||
| !is_ck_bwd_graph_capture_safe(bias_type, dropout, max_seqlen_q)){ |
There was a problem hiding this comment.
You should include here the deterministic as well
| static bool is_ck_bwd_graph_capture_safe( | ||
| NVTE_Bias_Type bias_type, | ||
| float dropout, | ||
| size_t max_seqlen_q) { |
There was a problem hiding this comment.
Add bool deterministic
| window_size_left, | ||
| window_size_right)){ | ||
| window_size_right, | ||
| is_training, cuda_graph)){ |
There was a problem hiding this comment.
Pass here the deterministic
|
The latest fixes for determinism seem not helping on gfx942 |
|
Alright looks like the failures are unrelated now. |
| if(bytes == 0){ | ||
| return nullptr; | ||
| } | ||
| constexpr size_t kAlign = 256; |
There was a problem hiding this comment.
Where is this kAlign=256 coming from?
| is_training, Q_type, KV_type, qkv_layout, bias_type, attn_mask_type, softmax_type, dropout, | ||
| h_q, h_kv, max_seqlen_q, max_seqlen_kv, d_qk, d_v, window_size_left, window_size_right, | ||
| return_max_logit, cuda_graph, false); | ||
| return_max_logit, false, false); |
There was a problem hiding this comment.
Do we enable cuda_graph=true before?
There was a problem hiding this comment.
It was ignored before, so we can set it to false arbitrarily. I've added a comment clarifying this.
fec6d6b to
cf46085
Compare
| // illegal under HIP-graph capture. So reserve a capture-safe upper bound instead. | ||
| // | ||
| // The dq_acc split count is ceil(seqlen_k / kN0) where kN0 is the dispatched bwd KV tile | ||
| // (bn0). The largest bn0 across supported archs is kCkBwdMaxKvTile (per the CK codegen bwd |
There was a problem hiding this comment.
bn0 is the same as kN0?
There was a problem hiding this comment.
Yes, it's a naming difference in different parts of the backend, but it's passed as the same var.
| // least one extra split for any actually-dispatched kN0 (all <= kCkBwdMaxKvTile), which | ||
| // covers inter-sequence padding of up to a whole tile per sequence -- far above the | ||
| // few-token THD alignment padding used in practice. | ||
| constexpr uint64_t kCkBwdMaxKvTile = 256; |
There was a problem hiding this comment.
Emm, this const is copied from CK source code? If so, it may be changed later in CK which can cause our issue.
| const size_t a16_hdim = (args.d_qk == 192) ? 192 : 128; | ||
| const size_t dq_acc_seq = args.is_v3_atomic_fp32 ? seqlen_q : a16_seq; | ||
| const size_t dq_acc_hdim = args.is_v3_atomic_fp32 ? args.d_qk : a16_hdim; | ||
| const size_t eff_batch = (args.is_group_mode() && args.is_v3_atomic_fp32) ? 1 : args.b; |
There was a problem hiding this comment.
In my mind, effective batch should be related to whether it's in group mode or not. bf16 or fp32 atomic mode should not affect it.
There was a problem hiding this comment.
This is based off of the mha_bwd section: https://github.com/ROCm/aiter/blob/028756633e4192785217838f4924dc16516f5780/csrc/cpp_itfs/mha_bwd.cu#L571-L601
There was a problem hiding this comment.
Okay, let's put a comment of this code pointer so in the future we can understand where this piece of hardcoding code is from.
| // host-side; v3 (asm) allocates only dq_acc. v3 is tried first but may fall | ||
| // back to v2, so reserve the larger of the two. The launcher symbol is forced | ||
| // local by QoLA's export script, so the v2 size is queried through QoLA. | ||
| const size_t v2_bytes = QOLA_NS(mha_bwd_workspace_size)(make_bwd_traits(args)); |
There was a problem hiding this comment.
Can you remind me where the mha_bwd_workspace_size is defined?
If the v2_bytes sometimes under estimate the real CK needs, can we change the mha_bwd_workspace_size there? Then we don't need to have std::max over three items. (We can just std::max over v3 asm needs and v2 ck needs)
There was a problem hiding this comment.
nit: if mha_bwd_workspace_size is defined in CK or qola, maybe should also put v3_dq_acc_bytes into qola
| const size_t a16_hdim = (args.d_qk == 192) ? 192 : 128; | ||
| const size_t dq_acc_seq = args.is_v3_atomic_fp32 ? seqlen_q : a16_seq; | ||
| const size_t dq_acc_hdim = args.is_v3_atomic_fp32 ? args.d_qk : a16_hdim; | ||
| const size_t eff_batch = (args.is_group_mode() && args.is_v3_atomic_fp32) ? 1 : args.b; |
There was a problem hiding this comment.
Okay, let's put a comment of this code pointer so in the future we can understand where this piece of hardcoding code is from.
| } | ||
| const size_t seqlen_q = args.is_group_mode() ? args.max_tokens_q : args.s_q; | ||
| const size_t elem = args.is_v3_atomic_fp32 ? 4 : 2; | ||
| const size_t a16_seq = (args.s_q + 15) / 16 * 16; |
There was a problem hiding this comment.
In the future, let's add non 16 multiple sq's to our unit tests to see what will happen.
| // host-side; v3 (asm) allocates only dq_acc. v3 is tried first but may fall | ||
| // back to v2, so reserve the larger of the two. The launcher symbol is forced | ||
| // local by QoLA's export script, so the v2 size is queried through QoLA. | ||
| const size_t v2_bytes = QOLA_NS(mha_bwd_workspace_size)(make_bwd_traits(args)); |
There was a problem hiding this comment.
nit: if mha_bwd_workspace_size is defined in CK or qola, maybe should also put v3_dq_acc_bytes into qola
| fmha_args.mask_type = static_cast<int>(static_cast<mask_enum>(args.attn_mask_type)); | ||
| fmha_args.use_asm_v3 = args.uses_bwd_v3; | ||
| // Mirrors AITER's small-seqlen guard at aiter/ops/mha.py:1689. | ||
| fmha_args.use_asm_v3 = (args.s_q < 16) ? false : args.uses_bwd_v3; |
There was a problem hiding this comment.
nit: have such a testcase (s_q<16) to see if things work as our expectation
There was a problem hiding this comment.
We already have several where s_q=1 which trigger this code path. Specifically it was put in as a response to a failing test case originally.
Description
Updates QoLA as well as moves up the pinned AITER commit
Fixes # (issue)
Type of change
Changes
Please list the changes introduced in this PR:
Checklist: