char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
eafe15a5e
char/aliceai-t5-moe
1#ifndef HTP_FLASH_ATTN_OPS_H 2#define HTP_FLASH_ATTN_OPS_H 3 4#include <stdint.h> 5#include <stddef.h> 6#include <stdbool.h> 7 8#include "hex-fastdiv.h" 9#include "hex-common.h" 10#include "htp-vtcm.h" 11 12#ifdef __cplusplus 13extern "C" { 14#endif 15 16// Tile constants (mirrored from hmx-utils.h for use on host side if needed) 17#define HTP_FA_HMX_TILE_SIZE 2048 18#define HMX_FP16_TILE_SIZE 2048 19#define HMX_FP16_TILE_N_ROWS 32 20#define HMX_FP16_TILE_N_COLS 32 21#define HMX_FP16_TILE_N_ELMS 1024 22 23#define HVX_FA_DMA_CACHE_SIZE 128 24#define HMX_FA_DMA_CACHE_SIZE 4 25 26 27#define HTP_FA_M_INITIAL_VAL -10000.0f 28 29enum htp_fa_kernel_type { 30HTP_FA_KERNEL_UNSUPPORTED = 0 , 31HTP_FA_KERNEL_HVX , 32HTP_FA_KERNEL_HMX 33}; 34 35struct htp_fa_kernel_params { 36uint8_t kernel_type ;// enum htp_fa_kernel_type 37uint8_t is_q_fp32 ;// 1 = Q type is F32, 0 = F16 38uint8_t is_dst_fp32 ;// 1 = dst type is F32, 0 = F16 39uint8_t n_threads ;// Number of threads to run 40 41// Common parameters 42uint16_t Br ; 43uint16_t Bc ; 44uint16_t n_kv_blocks ;// also HVX's n_blocks 45uint16_t G ;// GQA factor (n_heads / n_kv_heads) 46 47float scale ; 48float max_bias ; 49float logit_softcap ; 50uint32_t vtcm_size ; 51 52uint32_t qrows ; 53uint32_t qrows_per_thread ; 54uint32_t qrow_start ; 55float m0 ; 56float m1 ; 57uint32_t n_head_log2 ; 58 59struct fastdiv_values src3_div2 ; 60struct fastdiv_values src3_div3 ; 61 62struct fastdiv_values broadcast_rk2 ; 63struct fastdiv_values broadcast_rk3 ; 64struct fastdiv_values broadcast_rv2 ; 65struct fastdiv_values broadcast_rv3 ; 66 67union { 68struct { 69uint32_t g_br ; 70uint32_t row_buf_stride ; 71uint32_t mask_buf_row_stride ; 72int32_t mask_broadcast ; 73int32_t pipeline ; 74struct fastdiv_values div_G ; 75 }hmx ; 76struct { 77uint32_t size_q_row_padded ; 78uint32_t size_k_row_padded ; 79uint32_t size_v_row_padded ; 80struct fastdiv_values src0_div21 ; 81struct fastdiv_values src0_div1 ; 82 }hvx ; 83 }u ; 84}; 85 86#if defined(__cplusplus ) 87static_assert (sizeof (struct htp_fa_kernel_params ) <=128 ,"htp_fa_kernel_params is too large for kernel_params blob" ); 88#endif 89 90// VTCM region layout for the HMX flash-attention kernel. 91// 92// Single source of truth for both the host (which needs the total size to pick a 93// (Br, Bc) tiling that fits the VTCM budget) and the device (which needs the actual 94// byte offsets to place each scratch buffer). Building the layout once and reading 95// offsets/total from it makes host estimate and device allocation impossible to 96// desync -- previously they were duplicated formulas in two files and drifted. 97// 98// All fields are byte offsets / byte sizes -- no HVX_Vector type is named here so the 99// header stays host-includable. The device casts (base + off_*) to the proper type. 100// An offset of 0 marks a region that is not allocated for this configuration (only 101// off_v_tiles[1], which exists only when pipelining); the device sets such pointers NULL. 102struct hmx_fa_vtcm_layout { 103// Byte offsets from vtcm_base for each region. 104size_t off_q_tiles ; 105size_t off_q_dma ; 106size_t off_o_tiles [2 ]; 107size_t off_k_fp16 [2 ]; 108size_t off_v_fp16 [2 ]; 109size_t off_k_tiles [2 ]; 110size_t off_v_tiles [2 ]; 111size_t off_s_tiles [2 ]; 112size_t off_p_tiles [2 ]; 113size_t off_d_tiles [2 ]; 114size_t off_d_inv_l ; 115size_t off_m_vec ; 116size_t off_l_vec ; 117size_t off_s_rowmax ; 118size_t off_p_rowsum ; 119size_t off_row_bufs ; 120size_t off_hmx_scales_id ; 121size_t off_hmx_scales_qk ; 122size_t off_mask_buf ; 123size_t off_slopes ; 124 125// Region byte sizes reused by the device at runtime (not just for allocation). 126size_t q_tile_bytes ; 127size_t o_tile_bytes ; 128size_t s_tile_bytes ;// S and P tiles (same size) 129size_t d_tile_bytes ;// d_tiles[0..1] + d_inv_l, allocated back to back 130size_t m_line_bytes ;// one mask row 131size_t m_buf_slot_bytes ;// one dma_cache slot = align_up(Br * m_line_bytes, 4096) 132size_t col_vec_bytes ; 133 134// Derived strides. 135size_t row_buf_stride ;// HVX vectors (128B) per row buffer 136size_t mask_buf_row_stride ;// __fp16 elements per row in the mask buffer 137 138bool pipeline ; 139size_t total_bytes ; 140}; 141 142// Build the VTCM layout. 143 144static inline void hmx_fa_vtcm_layout_build (struct hmx_fa_vtcm_layout * L , 145size_t gqa_factor ,size_t DK ,size_t DV , 146size_t Br ,size_t Bc ,size_t n_threads ,bool pipeline ,bool is_q_fp32 ) { 147const size_t g_br = hex_align_up (gqa_factor * Br ,HMX_FP16_TILE_N_ROWS ); 148const size_t q_tile_size = hex_align_up (g_br * DK * sizeof (__fp16 ),HTP_FA_HMX_TILE_SIZE ); 149const size_t o_tile_size = hex_align_up (g_br * DV * sizeof (__fp16 ),HTP_FA_HMX_TILE_SIZE ); 150const size_t k_tile_size = hex_align_up (Bc * DK * sizeof (__fp16 ),HTP_FA_HMX_TILE_SIZE ); 151const size_t v_tile_size = hex_align_up (Bc * DV * sizeof (__fp16 ),HTP_FA_HMX_TILE_SIZE ); 152const size_t s_tile_size = hex_align_up (g_br * Bc * sizeof (__fp16 ),HTP_FA_HMX_TILE_SIZE ); 153 154// The rescale matrices are diagonal: the HMX kernels only ever load the g_br/32 155// tiles that sit on the diagonal, so store just those, packed back to back with 156// a stride of one tile. The old [g_br, g_br] square layout allocated g_br/32 157// times more than it used, which is also why a second D buffer was unaffordable. 158const size_t d_tile_size = (g_br /HMX_FP16_TILE_N_ROWS )* HTP_FA_HMX_TILE_SIZE ; 159 160const size_t q_dma_size = hex_align_up (g_br * DK * (is_q_fp32 ?sizeof (float ) :sizeof (__fp16 )),128 ); 161const size_t k_dma_size = hex_align_up (Bc * hex_round_up (DK * sizeof (__fp16 ),128 ),128 ); 162const size_t v_dma_size = hex_align_up (Bc * hex_round_up (DV * sizeof (__fp16 ),128 ),128 ); 163const size_t col_vec_size = hex_align_up (g_br * sizeof (float ),256 ); 164const size_t row_vec_size = hex_align_up (Bc * sizeof (__fp16 ),256 ); 165const size_t m_line_size = hex_align_up (Bc * sizeof (__fp16 ),128 ); 166const size_t m_buf_slot = hex_align_up (Br * m_line_size ,256 ); 167const size_t m_buf_size = m_buf_slot * HMX_FA_DMA_CACHE_SIZE ; 168const size_t slopes_size = hex_align_up (g_br * sizeof (__fp16 ),128 ); 169 170size_t off = 0 ; 171 172// Group A (Part 1 - HMX Tiled buffers) 173VTCM_LAYOUT_ALLOC (off ,off_q_tiles ,q_tile_size ); 174VTCM_LAYOUT_ALLOC (off ,off_o_tiles [0 ],o_tile_size ); 175VTCM_LAYOUT_ALLOC (off ,off_o_tiles [1 ],o_tile_size ); 176VTCM_LAYOUT_ALLOC (off ,off_d_tiles [0 ],d_tile_size ); 177VTCM_LAYOUT_ALLOC_OPTIONAL (off ,off_d_tiles [1 ],d_tile_size ,pipeline ); 178VTCM_LAYOUT_ALLOC (off ,off_d_inv_l ,d_tile_size ); 179 180// Group B & C share start offset (Group B tiles must be 2KB aligned) 181size_t off_group_b_c = hex_align_up (off ,HTP_FA_HMX_TILE_SIZE ); 182 183// Group B: Compute-only buffers 184size_t off_group_b = off_group_b_c ; 185VTCM_LAYOUT_ALLOC (off_group_b ,off_k_tiles [0 ],k_tile_size ); 186VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_k_tiles [1 ],k_tile_size ,pipeline ); 187VTCM_LAYOUT_ALLOC (off_group_b ,off_v_tiles [0 ],v_tile_size ); 188VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_v_tiles [1 ],v_tile_size ,pipeline ); 189VTCM_LAYOUT_ALLOC (off_group_b ,off_s_tiles [0 ],s_tile_size ); 190VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_s_tiles [1 ],s_tile_size ,pipeline ); 191VTCM_LAYOUT_ALLOC (off_group_b ,off_p_tiles [0 ],s_tile_size ); 192VTCM_LAYOUT_ALLOC_OPTIONAL (off_group_b ,off_p_tiles [1 ],s_tile_size ,pipeline ); 193VTCM_LAYOUT_ALLOC (off_group_b ,off_s_rowmax ,col_vec_size ); 194VTCM_LAYOUT_ALLOC (off_group_b ,off_p_rowsum ,col_vec_size ); 195VTCM_LAYOUT_ALLOC (off_group_b ,off_row_bufs ,row_vec_size * 2 * n_threads ); 196 197const size_t group_b_size = off_group_b - off_group_b_c ; 198 199// Group C: Q fetch DMA buffer 200size_t off_group_c = off_group_b_c ; 201VTCM_LAYOUT_ALLOC (off_group_c ,off_q_dma ,q_dma_size ); 202 203const size_t group_c_size = off_group_c - off_group_b_c ; 204 205off = off_group_b_c + hex_smax (group_b_size ,group_c_size ); 206 207// Group A (Part 2 - remaining non-HMX buffers) 208VTCM_LAYOUT_ALLOC (off ,off_k_fp16 [0 ],k_dma_size ); 209VTCM_LAYOUT_ALLOC (off ,off_k_fp16 [1 ],k_dma_size ); 210VTCM_LAYOUT_ALLOC (off ,off_v_fp16 [0 ],v_dma_size ); 211VTCM_LAYOUT_ALLOC (off ,off_v_fp16 [1 ],v_dma_size ); 212VTCM_LAYOUT_ALLOC (off ,off_m_vec ,col_vec_size ); 213VTCM_LAYOUT_ALLOC (off ,off_l_vec ,col_vec_size ); 214VTCM_LAYOUT_ALLOC (off ,off_hmx_scales_id ,256 ); 215VTCM_LAYOUT_ALLOC (off ,off_hmx_scales_qk ,256 ); 216VTCM_LAYOUT_ALLOC (off ,off_mask_buf ,m_buf_size ); 217VTCM_LAYOUT_ALLOC (off ,off_slopes ,slopes_size ); 218 219L -> q_tile_bytes = q_tile_size ; 220L -> o_tile_bytes = o_tile_size ; 221L -> col_vec_bytes = col_vec_size ; 222L -> s_tile_bytes = s_tile_size ; 223// Measured from the actual offsets rather than assumed to be N * d_tile_size, so 224// that inserting a region between them (or adding padding to VTCM_LAYOUT_ALLOC) 225// cannot silently leave the tail of the run unzeroed. 226L -> d_tile_bytes = (L -> off_d_inv_l + d_tile_size )- L -> off_d_tiles [0 ]; 227L -> m_line_bytes = m_line_size ; 228L -> m_buf_slot_bytes = m_buf_slot ; 229L -> row_buf_stride = row_vec_size /128 ; 230L -> mask_buf_row_stride = m_line_size /sizeof (__fp16 ); 231L -> pipeline = pipeline ; 232L -> total_bytes = off ; 233} 234 235// Exact VTCM usage for a given (gqa_factor, DK, DV, Br, Bc) configuration. 236static inline size_t hmx_fa_compute_vtcm_usage (size_t gqa_factor ,size_t DK ,size_t DV ,size_t Br ,size_t Bc ,size_t n_threads ,bool pipeline ,bool is_q_fp32 ) { 237struct hmx_fa_vtcm_layout L ; 238hmx_fa_vtcm_layout_build (& L ,gqa_factor ,DK ,DV ,Br ,Bc ,n_threads ,pipeline ,is_q_fp32 ); 239return L .total_bytes ; 240} 241 242#define FA_HVX_BLOCK_SIZE 64 243 244static inline size_t hvx_fa_compute_vtcm_usage (size_t DK ,size_t DV ,bool is_q_fp32 ,bool has_mask ,size_t n_threads ) { 245const size_t size_q_row_padded = hex_round_up (DK * (is_q_fp32 ?4 :2 ),128 ); 246const size_t size_k_row_padded = hex_round_up (DK * sizeof (__fp16 ),128 ); 247const size_t size_v_row_padded = hex_round_up (DV * sizeof (__fp16 ),128 ); 248 249const size_t size_q_block = size_q_row_padded * 1 ; 250const size_t size_k_block = size_k_row_padded * FA_HVX_BLOCK_SIZE ; 251const size_t size_v_block = size_v_row_padded * FA_HVX_BLOCK_SIZE ; 252const size_t size_m_block = hex_round_up (FA_HVX_BLOCK_SIZE * sizeof (__fp16 ),128 ); 253const size_t size_vkq_acc = hex_round_up (DV * sizeof (float ),128 ); 254 255const size_t size_per_thread = size_q_block * 1 256+ size_k_block * 2 257+ size_v_block * 2 258+ (has_mask ?size_m_block * HVX_FA_DMA_CACHE_SIZE :0 ) 259+ size_vkq_acc ; 260 261return size_per_thread * n_threads ; 262} 263 264#define FA_MIN_KV_BLOCKS 3 265 266// Cost-based (Br, Bc) search for flash attention with pipeline constraint. 267static inline int hmx_fa_find_chunk_size (size_t * Br_out , 268size_t * Bc_out , 269size_t gqa_factor , 270size_t DK , 271size_t DV , 272size_t qo_len , 273size_t kv_len , 274size_t vtcm_budget , 275size_t n_threads , 276bool is_q_fp32 ) { 277const size_t T = HMX_FP16_TILE_N_ROWS ;// 32 278const size_t br_unit = hmx_ceil_div (T ,gqa_factor ); 279const size_t bc_unit = HMX_FP16_TILE_N_COLS * 2 ;// 64 280const bool can_pipeline = (kv_len >=FA_MIN_KV_BLOCKS * bc_unit && n_threads >=2 ); 281 282// Br_max: largest Br aligned to br_unit that does not exceed qo_len. 283const size_t Br_max = qo_len >=br_unit ?hex_align_down (qo_len ,br_unit ) :br_unit ; 284 285// Pipeline constraint: cap Bc so n_kv_blocks >= FA_MIN_KV_BLOCKS. 286// Only relax when kv_len is too short to form enough blocks. 287const size_t Bc_limit = can_pipeline ?hex_align_down (kv_len /FA_MIN_KV_BLOCKS ,bc_unit ) : 288 (kv_len >=bc_unit ?hex_align_down (kv_len ,bc_unit ) :bc_unit ); 289// Cost coefficients calibrated from profiling 290const size_t c_q_fixed = 800 ;// per-Q-block: q_load + epilogue o_update + o_norm + o_store 291const size_t c_iter_base = 200 ;// per-KV-iter base (HMX dot/update + DMA) 292const size_t c_softmax = 600 ;// per 64-row vector chunk on HVX 293 294size_t best_cost = SIZE_MAX ,best_mn = 0 ; 295size_t best_Br = 0 ,best_Bc = 0 ; 296 297for (size_t Br = Br_max ;Br >=br_unit ;Br -= br_unit ) { 298// Try all Bc candidates from Bc_limit down to bc_unit 299for (size_t Bc = Bc_limit ;Bc >=bc_unit ;Bc -= bc_unit ) { 300size_t vtcm_needed = hmx_fa_compute_vtcm_usage (gqa_factor ,DK ,DV ,Br ,Bc ,n_threads ,can_pipeline ,is_q_fp32 ); 301if (vtcm_needed <=vtcm_budget ) { 302// This Bc fits for this Br! 303const size_t q_blocks = (qo_len + Br - 1 ) /Br ; 304const size_t kv_blocks = (kv_len + Bc - 1 ) /Bc ; 305const size_t actual_threads = (kv_blocks >=3 && n_threads >=2 ) ?n_threads :1 ; 306const size_t n_rows_g = Br * gqa_factor ; 307const size_t n_row_vec_cnt = (n_rows_g + 63 ) /64 ; 308const size_t n_use = n_row_vec_cnt < actual_threads ?n_row_vec_cnt :actual_threads ; 309const size_t vecs_per_t = n_use > 0 ? (n_row_vec_cnt + n_use - 1 ) /n_use :1 ; 310 311const size_t c_iter_actual = c_iter_base + c_softmax * vecs_per_t ; 312const size_t cost = q_blocks * (c_q_fixed + kv_blocks * c_iter_actual ); 313const size_t mn = Br * Bc ; 314 315if (cost < best_cost || (cost == best_cost && mn > best_mn )) { 316best_cost = cost ; 317best_mn = mn ; 318best_Br = Br ; 319best_Bc = Bc ; 320 } 321// Since we iterate Bc from largest to smallest, this is the largest Bc that fits 322// for this Br. We can break to the next Br. 323break ; 324 } 325 } 326 327if (Br == br_unit ) { 328break ; 329 } 330 } 331 332if (best_Br == 0 || best_Bc == 0 ) { 333return -1 ; 334 } 335 336* Br_out = best_Br ; 337* Bc_out = best_Bc ; 338return 0 ; 339} 340 341#ifdef __cplusplus 342} 343#endif 344 345#endif /* HTP_FLASH_ATTN_OPS_H */