11# Copyright (c) 2025, Jay Shah, Ganesh Bikshandi, Ying Zhang, Vijay Thakkar, Pradeep Ramani, Tri Dao.
22# [2025-07-04] Version in Cute-DSL, for Hopper and Blackwell. You'll need install nvidia-cutlass-dsl==4.2.0.
33
4+ from numpy ._core .defchararray import zfill
45import os
56import math
67from dataclasses import dataclass
@@ -733,7 +734,7 @@ def _flash_attn_fwd(
733734 and not disable_scheduler_metadata
734735 and not use_dedicated_hd256_kernel
735736 ):
736- scheduler_metadata = get_scheduler_metadata (
737+ scheduler_metadata = _get_scheduler_metadata (
737738 num_batch = batch_size ,
738739 max_seqlen_q = max_seqlen_q ,
739740 max_seqlen_k = max_seqlen_k ,
@@ -2759,7 +2760,7 @@ def flash_attn_combine(
27592760 return out , lse
27602761
27612762
2762- def get_scheduler_metadata (
2763+ def _get_scheduler_metadata (
27632764 num_batch : int ,
27642765 max_seqlen_q : int ,
27652766 max_seqlen_k : int ,
@@ -2849,7 +2850,7 @@ def get_scheduler_metadata(
28492850 zfill_padded_output ,
28502851 )
28512852
2852- if cache_key not in get_scheduler_metadata .compile_cache :
2853+ if cache_key not in _get_scheduler_metadata .compile_cache :
28532854 (
28542855 num_m_blocks_cute ,
28552856 num_splits_dynamic_cute ,
@@ -2891,7 +2892,7 @@ def get_scheduler_metadata(
28912892 sort = sort ,
28922893 zfill_padded_output = zfill_padded_output ,
28932894 )
2894- get_scheduler_metadata .compile_cache [cache_key ] = cute .compile (
2895+ _get_scheduler_metadata .compile_cache [cache_key ] = cute .compile (
28952896 scheduler ,
28962897 max_seqlen_q ,
28972898 max_seqlen_k ,
@@ -2915,7 +2916,7 @@ def get_scheduler_metadata(
29152916 )
29162917
29172918 if not is_fake_mode ():
2918- get_scheduler_metadata .compile_cache [cache_key ](
2919+ _get_scheduler_metadata .compile_cache [cache_key ](
29192920 max_seqlen_q ,
29202921 max_seqlen_k ,
29212922 seqlen_k_new ,
@@ -2968,4 +2969,61 @@ def get_scheduler_metadata(
29682969 )
29692970
29702971
2971- get_scheduler_metadata .compile_cache = get_jit_cache ("scheduler_metadata" )
2972+ _get_scheduler_metadata .compile_cache = get_jit_cache ("scheduler_metadata" )
2973+
2974+
2975+ def get_scheduler_metadata (
2976+ max_seqlen_q : int ,
2977+ max_seqlen_k : int ,
2978+ nheads : int ,
2979+ nheads_kv : int ,
2980+ headdim : int ,
2981+ num_splits : int ,
2982+ headdim_v : Optional [int ] = None ,
2983+ pack_gqa : Optional [int ] = None ,
2984+ causal : bool = False ,
2985+ enable_pdl : bool = False ,
2986+ sort : bool = False ,
2987+ seqlen_k_new : int = 0 ,
2988+ cu_seqlens_q : Optional [torch .Tensor ] = None ,
2989+ cu_seqlens_k : Optional [torch .Tensor ] = None ,
2990+ cu_seqlens_k_new : Optional [torch .Tensor ] = None ,
2991+ seqused_q : Optional [torch .Tensor ] = None ,
2992+ seqused_k : Optional [torch .Tensor ] = None ,
2993+ leftpad_k : Optional [torch .Tensor ] = None ,
2994+ seqlen_k_per_split : Optional [int ] = None ,
2995+ ) -> SchedulerMetadataTensorsTorch :
2996+ """Public entrypoint for scheduler metadata computation"""
2997+ num_batch = cu_seqlens_q .shape [0 ] - 1 # TODO: ensure batch size consistent across tensors
2998+
2999+ # TODO: get tile size and q stage from heuristic (same as fwd)
3000+ tile_m = 128
3001+ tile_n = 128
3002+ q_stage = 1
3003+
3004+ return _get_scheduler_metadata (
3005+ num_batch ,
3006+ max_seqlen_q ,
3007+ max_seqlen_k ,
3008+ nheads ,
3009+ nheads_kv ,
3010+ headdim ,
3011+ num_splits ,
3012+ tile_m ,
3013+ tile_n ,
3014+ headdim_v = headdim_v ,
3015+ pack_gqa = pack_gqa ,
3016+ q_stage = q_stage ,
3017+ causal = causal ,
3018+ enable_pdl = enable_pdl ,
3019+ sort = sort ,
3020+ seqlen_k_new = seqlen_k_new ,
3021+ cu_seqlens_q = cu_seqlens_q ,
3022+ cu_seqlens_k = cu_seqlens_k ,
3023+ cu_seqlens_k_new = cu_seqlens_k_new ,
3024+ seqused_q = seqused_q ,
3025+ seqused_k = seqused_k ,
3026+ leftpad_k = leftpad_k ,
3027+ seqlen_k_per_split = seqlen_k_per_split ,
3028+ zfill_padded_output = True ,
3029+ )
0 commit comments