2626#include < tensorrt_llm/thop/outputTensor.h>
2727#include < tensorrt_llm/thop/trtllmGenFusedOps.h>
2828#include < torch/extension.h>
29+ #include < type_traits>
2930
3031namespace nb = nanobind;
3132
@@ -45,6 +46,93 @@ nb::object optionalToObject(std::optional<T> const& value)
4546 return nb::none ();
4647}
4748
49+ template <typename T>
50+ struct OptionalInner
51+ {
52+ };
53+
54+ template <typename T>
55+ struct OptionalInner <std::optional<T>>
56+ {
57+ using Type = T;
58+ };
59+
60+ template <typename T>
61+ inline constexpr bool kIsOptional = false ;
62+
63+ template <typename T>
64+ inline constexpr bool kIsOptional <std::optional<T>> = true ;
65+
66+ template <typename T>
67+ nb::object fmhaFieldToObject (T const & value)
68+ {
69+ if constexpr (std::is_enum_v<T>)
70+ {
71+ return nb::cast (static_cast <int64_t >(static_cast <std::underlying_type_t <T>>(value)));
72+ }
73+ else if constexpr (std::is_same_v<T, tensorrt_llm::common::QuantMode>)
74+ {
75+ return nb::cast (static_cast <int64_t >(value.value ()));
76+ }
77+ else
78+ {
79+ return nb::cast (value);
80+ }
81+ }
82+
83+ template <typename T>
84+ nb::object fmhaFieldToObject (std::optional<T> const & value)
85+ {
86+ if (value.has_value ())
87+ {
88+ return fmhaFieldToObject (*value);
89+ }
90+ return nb::none ();
91+ }
92+
93+ template <typename T>
94+ T castFmhaField (nb::object value)
95+ {
96+ if constexpr (std::is_enum_v<T>)
97+ {
98+ return static_cast <T>(static_cast <std::underlying_type_t <T>>(nb::cast<int64_t >(value)));
99+ }
100+ else if constexpr (std::is_same_v<T, tensorrt_llm::common::QuantMode>)
101+ {
102+ return T (static_cast <typename T::BaseType>(nb::cast<int64_t >(value)));
103+ }
104+ else
105+ {
106+ return nb::cast<T>(value);
107+ }
108+ }
109+
110+ template <typename FieldT>
111+ void bindFmhaParamField (nb::class_<torch_ext::FmhaParams>& cls, char const * name, FieldT torch_ext::FmhaParams::*member)
112+ {
113+ cls.def_prop_rw (
114+ name, [member](torch_ext::FmhaParams const & self) { return fmhaFieldToObject (self.*member); },
115+ [member](torch_ext::FmhaParams& self, nb::object value)
116+ {
117+ if constexpr (kIsOptional <FieldT>)
118+ {
119+ if (value.is_none ())
120+ {
121+ self.*member = std::nullopt ;
122+ }
123+ else
124+ {
125+ using InnerT = typename OptionalInner<FieldT>::Type;
126+ self.*member = castFmhaField<InnerT>(value);
127+ }
128+ }
129+ else
130+ {
131+ self.*member = castFmhaField<FieldT>(value);
132+ }
133+ });
134+ }
135+
48136nb::tuple trtllmGenContextPreprocessBinding (torch::Tensor qkv_input, torch::Tensor workspace,
49137 torch::Tensor sequence_lengths, torch::Tensor context_lengths, std::optional<torch::Tensor> kv_cache_block_offsets,
50138 std::optional<torch::Tensor> host_kv_cache_pool_pointers, std::optional<torch::Tensor> host_kv_cache_pool_mapping,
@@ -133,55 +221,23 @@ void initBindings(nb::module_& m)
133221 m.attr (kv.first ) = kv.second ;
134222 }
135223
136- m.def (" attention" , &torch_ext::attention,
137- // Parameters with default values: using std::nullopt for trailing optional arguments (omittable)
138- // and .none() for optional arguments followed by parameters without default values (not omittable).
139- nb::arg (" q" ), nb::arg (" k" ).none (), nb::arg (" v" ).none (), nb::arg (" output" ), nb::arg (" output_sf" ).none (),
140- nb::arg (" workspace_" ).none (), nb::arg (" sequence_length" ), nb::arg (" host_past_key_value_lengths" ),
141- nb::arg (" host_total_kv_lens" ), nb::arg (" context_lengths" ), nb::arg (" host_context_lengths" ),
142- nb::arg (" host_request_types" ), nb::arg (" max_context_q_len_override" ).none (),
143- nb::arg (" kv_cache_block_offsets" ).none (), nb::arg (" host_kv_cache_pool_pointers" ).none (),
144- nb::arg (" host_kv_cache_pool_mapping" ).none (), nb::arg (" cache_indirection" ).none (),
145- nb::arg (" kv_scale_orig_quant" ).none (), nb::arg (" kv_scale_quant_orig" ).none (), nb::arg (" out_scale" ).none (),
146- nb::arg (" rotary_inv_freq" ).none (), nb::arg (" rotary_cos_sin" ).none (), nb::arg (" latent_cache" ).none (),
147- nb::arg (" q_pe" ).none (), nb::arg (" block_ids_per_seq" ).none (), nb::arg (" attention_sinks" ).none (),
148- nb::arg (" is_fused_qkv" ), nb::arg (" update_kv_cache" ), nb::arg (" predicted_tokens_per_seq" ),
149- nb::arg (" local_layer_idx" ), nb::arg (" num_heads" ), nb::arg (" num_kv_heads" ), nb::arg (" head_size" ),
150- nb::arg (" tokens_per_block" ).none (), nb::arg (" max_num_requests" ), nb::arg (" max_context_length" ),
151- nb::arg (" max_seq_len" ), nb::arg (" attention_window_size" ), nb::arg (" beam_width" ), nb::arg (" mask_type" ),
152- nb::arg (" quant_mode" ), nb::arg (" q_scaling" ), nb::arg (" position_embedding_type" ), nb::arg (" rope_dim" ),
153- nb::arg (" rope_base" ), nb::arg (" rope_scale_type" ), nb::arg (" rope_scale" ), nb::arg (" rope_short_m_scale" ),
154- nb::arg (" rope_long_m_scale" ), nb::arg (" rope_max_positions" ), nb::arg (" rope_original_max_positions" ),
155- nb::arg (" use_paged_context_fmha" ), nb::arg (" attention_input_type" ).none (), nb::arg (" is_mla_enable" ),
156- nb::arg (" chunked_prefill_buffer_batch_size" ).none (), nb::arg (" q_lora_rank" ).none (),
157- nb::arg (" kv_lora_rank" ).none (), nb::arg (" qk_nope_head_dim" ).none (), nb::arg (" qk_rope_head_dim" ).none (),
158- nb::arg (" v_head_dim" ).none (), nb::arg (" rope_append" ).none (), nb::arg (" mrope_rotary_cos_sin" ).none (),
159- nb::arg (" mrope_position_deltas" ).none (), nb::arg (" helix_position_offsets" ).none (),
160- nb::arg (" helix_is_inactive_rank" ).none (), nb::arg (" attention_chunk_size" ).none (),
161- nb::arg (" softmax_stats_tensor" ).none (), nb::arg (" is_spec_decoding_enabled" ), nb::arg (" use_spec_decoding" ),
162- nb::arg (" is_spec_dec_tree" ), nb::arg (" spec_decoding_generation_lengths" ).none (),
163- nb::arg (" spec_decoding_position_offsets_for_cpp" ).none (), nb::arg (" spec_decoding_packed_mask" ).none (),
164- nb::arg (" spec_decoding_bl_tree_mask_offset" ).none (), nb::arg (" spec_decoding_bl_tree_mask" ).none (),
165- nb::arg (" spec_bl_tree_first_sparse_mask_offset_kv" ).none (), nb::arg (" sparse_kv_indices" ).none (),
166- nb::arg (" sparse_kv_offsets" ).none (), nb::arg (" sparse_attn_indices" ).none (),
167- nb::arg (" sparse_attn_offsets" ).none (), nb::arg (" sparse_attn_indices_block_size" ),
168- nb::arg (" num_sparse_topk" ) = std::nullopt , nb::arg (" sparse_attn_kv_lens" ) = std::nullopt ,
169- nb::arg (" skip_softmax_threshold_scale_factor_prefill" ) = std::nullopt ,
170- nb::arg (" skip_softmax_threshold_scale_factor_decode" ) = std::nullopt ,
171- nb::arg (" skip_softmax_stat" ) = std::nullopt , nb::arg (" cu_q_seqlens" ) = std::nullopt ,
172- nb::arg (" cu_kv_seqlens" ) = std::nullopt , nb::arg (" fmha_scheduler_counter" ) = std::nullopt ,
173- nb::arg (" mla_bmm1_scale" ) = std::nullopt , nb::arg (" mla_bmm2_scale" ) = std::nullopt ,
174- nb::arg (" quant_q_buffer" ) = std::nullopt , nb::arg (" flash_mla_tile_scheduler_metadata" ) = std::nullopt ,
175- nb::arg (" flash_mla_num_splits" ) = std::nullopt , nb::arg (" sage_attn_num_elts_per_blk_q" ) = 0 ,
176- nb::arg (" sage_attn_num_elts_per_blk_k" ) = 0 , nb::arg (" sage_attn_num_elts_per_blk_v" ) = 0 ,
177- nb::arg (" sage_attn_qk_int8" ) = false , nb::arg (" num_contexts" ) = 0 , nb::arg (" num_ctx_tokens" ) = 0 ,
178- nb::arg (" trtllm_gen_jit_warmup" ) = false , nb::arg (" aux_kv_cache_pool_ptr" ) = std::nullopt ,
179- nb::arg (" is_cross" ) = false , nb::arg (" cross_kv" ) = std::nullopt ,
180- nb::arg (" relative_attention_bias" ) = std::nullopt , nb::arg (" relative_attention_max_distance" ) = 0 ,
181- nb::arg (" spec_decoding_target_max_draft_tokens" ) = std::nullopt , nb::arg (" quant_scale_qkv" ) = std::nullopt ,
182- nb::arg (" dsv4_inv_rope_cos_sin_cache" ) = std::nullopt , nb::arg (" enable_dsv4_epilogue_fusion" ) = false ,
183- nb::arg (" force_prepare_spec_dec_tree_mask" ) = false , nb::arg (" max_num_sequences" ) = std::nullopt ,
184- " Multi-head attention operation" , nb::call_guard<nb::gil_scoped_release>());
224+ // ---- Phased attention API ----
225+ auto fmhaParams = nb::class_<torch_ext::FmhaParams>(m, " FmhaParams" ).def (nb::init<>());
226+ #define TRTLLM_FMHA_PARAM_FIELD (name, cpp_type, py_type, cpp_default, py_default ) \
227+ bindFmhaParamField (fmhaParams, #name, &torch_ext::FmhaParams::name);
228+ #include " tensorrt_llm/thop/fmha_params_fields.inc"
229+ #undef TRTLLM_FMHA_PARAM_FIELD
230+
231+ m.def (" run_context" , &torch_ext::run_context, nb::arg (" params" ), " Phased attention run_context." ,
232+ nb::call_guard<nb::gil_scoped_release>());
233+ m.def (" run_generation" , &torch_ext::run_generation, nb::arg (" params" ), " Phased attention run_generation." ,
234+ nb::call_guard<nb::gil_scoped_release>());
235+ m.def (" run_mla_generation" , &torch_ext::run_mla_generation, nb::arg (" params" ),
236+ " Phased attention run_mla_generation." , nb::call_guard<nb::gil_scoped_release>());
237+ m.def (" get_attention_workspace_size" , &torch_ext::get_attention_workspace_size, nb::arg (" params" ),
238+ nb::arg (" num_tokens" ), nb::arg (" max_attention_window_size" ), nb::arg (" num_gen_tokens" ),
239+ nb::arg (" max_blocks_per_sequence" ), nb::arg (" ctx_total_kv_len" ) = 0 ,
240+ " Max of the context/generation workspace byte requirements for sizing FmhaParams.workspace." );
185241
186242 m.def (
187243 " get_helix_workspace_size_per_rank" ,
0 commit comments