char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
21f6b0d22
char/aliceai-t5-moe
1// This file defines tests for various GGML ops and backends. 2// For the forward pass it asserts that the results of multiple backends computing the same GGML ops are consistent. 3// For the backward pass it asserts that the gradients from backpropagation are consistent 4// with the gradients obtained via the method of finite differences ("grad" mode, this is optional). 5// It is also possible to check the performance ("perf" mode). 6// 7// this file has three sections: Section 1 does general setup, section 2 defines the GGML ops to be tested, 8// and section 3 defines which tests to run. 9// Quick start for adding a new GGML op: Go to section 2 and create a struct that inherits from test_case, 10// then go to section 3 and add an instantiation of your struct. 11 12 13// ############################## 14// ## Section 1: General Setup ## 15// ############################## 16 17 18#include "ggml.h" 19#include "ggml-alloc.h" 20#include "ggml-backend.h" 21#include "ggml-cpp.h" 22 23#include <algorithm> 24#include <atomic> 25#include <array> 26#include <cfloat> 27#include <cinttypes> 28#include <cstdarg> 29#include <cstdint> 30#include <cstdio> 31#include <cstdlib> 32#include <cstring> 33#include <ctime> 34#include <future> 35#include <fstream> 36#include <memory> 37#include <mutex> 38#include <random> 39#include <regex> 40#include <set> 41#include <sstream> 42#include <string> 43#include <string_view> 44#include <thread> 45#include <vector> 46#include <unordered_map> 47 48#ifdef __EMSCRIPTEN__ 49# define N_THREADS 1 50#else 51# define N_THREADS std::thread::hardware_concurrency() 52#endif 53 54static void init_tensor_uniform (ggml_tensor * tensor ,float min = -1.0f ,float max = 1.0f ) { 55size_t nels = ggml_nelements (tensor ); 56 std::vector < float > data (nels ); 57 { 58// parallel initialization 59static const size_t n_threads = std::max < size_t > (1 , std::min < size_t > (nels /1024 , std::min < size_t > (4 ,N_THREADS /2 ))); 60 61auto init_thread = [& ](size_t start ,size_t end ) { 62 thread_local std::default_random_engine gen (std::random_device {}()); 63 std::uniform_real_distribution < float > distribution (min ,max ); 64for (size_t i = start ;i < end ;i ++ ) { 65data [i ]= distribution (gen ); 66 } 67 }; 68 69if (n_threads == 1 ) { 70init_thread (0 ,nels ); 71 }else { 72 std::vector < std::future < void >> tasks ; 73tasks .reserve (n_threads ); 74for (size_t i = 0 ;i < n_threads ;i ++ ) { 75size_t start = i * nels /n_threads ; 76size_t end = (i + 1 )* nels /n_threads ; 77tasks .push_back (std::async (std::launch::async ,init_thread ,start ,end )); 78 } 79for (auto & t :tasks ) { 80t .get (); 81 } 82 } 83 } 84 85if (tensor -> type == GGML_TYPE_F32 || tensor -> type == GGML_TYPE_I32 ) { 86ggml_backend_tensor_set (tensor ,data .data (),0 ,nels * sizeof (float )); 87 }else if (ggml_is_quantized (tensor -> type )|| tensor -> type == GGML_TYPE_F16 || tensor -> type == GGML_TYPE_BF16 ) { 88GGML_ASSERT (nels %ggml_blck_size (tensor -> type )== 0 ); 89 90// dummy importance matrix 91 std::vector < float > imatrix (tensor -> ne [0 ],1.0f ); 92const float * im = imatrix .data (); 93if (!ggml_quantize_requires_imatrix (tensor -> type )) { 94// when the imatrix is optional, we want to test both quantization with and without imatrix 95// use one of the random numbers to decide 96if (data [0 ]> 0.5f * (min + max )) { 97im = nullptr ; 98 } 99 } 100 101 std::vector < uint8_t > dataq (ggml_row_size (tensor -> type ,nels )); 102 { 103// parallel quantization by block 104size_t blck_size = ggml_blck_size (tensor -> type ); 105size_t n_blocks = nels /blck_size ; 106 107auto quantize_thread = [& ](size_t start ,size_t end ) { 108ggml_quantize_chunk (tensor -> type ,data .data (),dataq .data (), 109start * blck_size ,end - start ,blck_size ,im ); 110 }; 111 112const size_t min_blocks_per_thread = 1 ; 113const size_t n_quant_threads = std::min < size_t > (std::max < size_t > (N_THREADS /2 ,1 ), 114 std::max < size_t > (1 ,n_blocks /min_blocks_per_thread )); 115 116if (n_quant_threads == 1 ) { 117// single-threaded quantization: do all blocks in the current thread 118quantize_thread (0 ,n_blocks ); 119 }else { 120 std::vector < std::future < void >> tasks ; 121tasks .reserve (n_quant_threads ); 122for (size_t i = 0 ;i < n_quant_threads ;i ++ ) { 123size_t start = i * n_blocks /n_quant_threads ; 124size_t end = (i + 1 )* n_blocks /n_quant_threads ; 125tasks .push_back (std::async (std::launch::async ,quantize_thread ,start ,end )); 126 } 127for (auto & t :tasks ) { 128t .get (); 129 } 130 } 131 } 132ggml_backend_tensor_set (tensor ,dataq .data (),0 ,dataq .size ()); 133 }else if (tensor -> type == GGML_TYPE_I8 || tensor -> type == GGML_TYPE_I16 ) { 134// This is going to create some weird integers though. 135ggml_backend_tensor_set (tensor ,data .data (),0 ,nels * ggml_type_size (tensor -> type )); 136 }else if (tensor -> type == GGML_TYPE_I64 ) { 137// Integers with a size of 8 bytes can be set by mirroring the float data, the specific values are again not really meaningful. 138const size_t nbytes_half = nels * sizeof (float ); 139ggml_backend_tensor_set (tensor ,data .data (),0 * nbytes_half ,nbytes_half ); 140ggml_backend_tensor_set (tensor ,data .data (),1 * nbytes_half ,nbytes_half ); 141 }else { 142GGML_ABORT ("fatal error" ); 143 } 144} 145 146// generate an F16 mask where certain blocks are randomly masked with -INF value 147static void init_tensor_kq_mask (ggml_tensor * tensor ,float min = -1.0f ,float max = 1.0f ) { 148GGML_ASSERT (tensor -> type == GGML_TYPE_F16 ); 149 150GGML_TENSOR_LOCALS (int32_t ,ne ,tensor ,ne ); 151 152 std::vector < float > data_f32 (ne0 * ne1 * ne2 * ne3 ); 153 std::vector < ggml_fp16_t > data_f16 (ne0 * ne1 * ne2 * ne3 ); 154 155 std::random_device rd ; 156 std::mt19937 gen (rd ()); 157 std::uniform_real_distribution < float > dis (min ,max ); 158 159for (size_t i = 0 ;i < data_f32 .size ();i ++ ) { 160data_f32 [i ]= dis (gen ); 161 } 162 163// block size 164const int blck0 = 128 ; 165const int blck1 = 64 ; 166 167// number of INF/zero blocks 168const int n_inf_zero_blocks = 0.2 * (ne0 * ne1 * ne2 * ne3 )/(blck0 * blck1 ); 169 170for (int b = 0 ;b < n_inf_zero_blocks ;b ++ ) { 171const int p3 = (rd () %ne3 ); 172const int p2 = (rd () %ne2 ); 173const int p1 = (rd () %ne1 ); 174const int p0 = (rd () %ne0 ); 175 176bool inf = rd ()& 1 ; 177 178for (int i1 = 0 ;i1 < blck1 && p1 + i1 < ne1 ;i1 ++ ) { 179const int idx = p3 * ne2 * ne1 * ne0 + p2 * ne1 * ne0 + (p1 + i1 )* ne0 + p0 ; 180 181for (int i0 = 0 ;i0 < blck0 && p0 + i0 < ne0 ;i0 ++ ) { 182data_f32 [idx + i0 ]= inf ?- INFINITY :0.0f ; 183 } 184 } 185 } 186 187ggml_fp32_to_fp16_row (data_f32 .data (),data_f16 .data (),ne0 * ne1 * ne2 * ne3 ); 188 189ggml_backend_tensor_set (tensor ,data_f16 .data (),0 ,data_f16 .size ()* sizeof (ggml_fp16_t )); 190} 191 192static void init_tensor_kq_mask_sparse (ggml_tensor * tensor ,int64_t n_kv_max ) { 193GGML_ASSERT (tensor -> type == GGML_TYPE_F16 ); 194GGML_ASSERT (n_kv_max > 0 && n_kv_max <=tensor -> ne [0 ]); 195 196const int64_t ne0 = tensor -> ne [0 ]; 197const int64_t nrows = ggml_nrows (tensor ); 198 std::vector < float > data_f32 (ggml_nelements (tensor ),- INFINITY ); 199 std::vector < ggml_fp16_t > data_f16 (ggml_nelements (tensor )); 200 std::vector < int32_t > order (ne0 ); 201for (int64_t i = 0 ;i < ne0 ;++ i ) { 202order [i ]= i ; 203 } 204 205 std::mt19937 gen (0x5A17 ); 206for (int64_t row = 0 ;row < nrows ;++ row ) { 207 std::shuffle (order .begin (),order .end (),gen ); 208const int64_t count = n_kv_max - row % std::min < int64_t > (n_kv_max ,17 ); 209 std::sort (order .begin (),order .begin ()+ count ); 210for (int64_t i = 0 ;i < count ;++ i ) { 211data_f32 [row * ne0 + order [i ]]= -0.03125f * (1 + (i + row ) %7 ); 212 } 213 } 214 215ggml_fp32_to_fp16_row (data_f32 .data (),data_f16 .data (),data_f16 .size ()); 216ggml_backend_tensor_set (tensor ,data_f16 .data (),0 ,data_f16 .size ()* sizeof (ggml_fp16_t )); 217} 218 219// generate a lower triangular matrix 220static void init_tensor_tril (ggml_tensor * tensor ,float min = -1.0f ,float max = 1.0f ) { 221GGML_ASSERT (tensor -> type == GGML_TYPE_F32 ); 222GGML_ASSERT (tensor -> ne [0 ]== tensor -> ne [1 ]); 223 224GGML_TENSOR_LOCALS (int32_t ,ne ,tensor ,ne ); 225GGML_TENSOR_LOCALS (size_t ,nb ,tensor ,nb ); 226 227 std::vector < float > data_f32 (ne0 * ne1 * ne2 * ne3 ); 228 229 std::random_device rd ; 230 std::mt19937 gen (rd ()); 231 std::uniform_real_distribution < float > dis (min ,max ); 232 233for (int64_t i3 = 0 ;i3 < ne3 ;i3 ++ ) { 234for (int64_t i2 = 0 ;i2 < ne2 ;i2 ++ ) { 235for (int64_t i1 = 0 ;i1 < ne1 ;i1 ++ ) { 236for (int64_t i0 = 0 ;i0 < ne0 ;i0 ++ ) { 237int64_t idx = (i0 * nb0 + i1 * nb1 + i2 * nb2 + i3 * nb3 ) /sizeof (float ); 238if (i0 <=i1 ) { 239data_f32 [idx ]= dis (gen ); 240 }else { 241data_f32 [idx ]= 0.0f ; 242 } 243 } 244 } 245 } 246 } 247 248ggml_backend_tensor_set (tensor ,data_f32 .data (),0 ,ggml_nbytes (tensor )); 249} 250 251static std::vector < float > tensor_to_float (const ggml_tensor * t ) { 252 std::vector < float > tv ; 253tv .reserve (ggml_nelements (t )); 254 255 std::vector < uint8_t > buf (ggml_nbytes (t )); 256ggml_backend_tensor_get (t ,buf .data (),0 ,ggml_nbytes (t )); 257 258const auto * tt = ggml_get_type_traits (t -> type ); 259size_t bs = ggml_blck_size (t -> type ); 260 std::vector < float > vq (ggml_blck_size (t -> type )); 261bool quantized = ggml_is_quantized (t -> type ); 262 263// access elements by index to avoid gaps in views 264for (int64_t i3 = 0 ;i3 < t -> ne [3 ];i3 ++ ) { 265for (int64_t i2 = 0 ;i2 < t -> ne [2 ];i2 ++ ) { 266for (int64_t i1 = 0 ;i1 < t -> ne [1 ];i1 ++ ) { 267for (int64_t i0 = 0 ;i0 < t -> ne [0 ];i0 += bs ) { 268size_t i = i3 * t -> nb [3 ]+ i2 * t -> nb [2 ]+ i1 * t -> nb [1 ]+ i0 /bs * t -> nb [0 ]; 269if (t -> type == GGML_TYPE_F16 ) { 270tv .push_back (ggml_fp16_to_fp32 (* (ggml_fp16_t * )& buf [i ])); 271 }else if (t -> type == GGML_TYPE_BF16 ) { 272tv .push_back (ggml_bf16_to_fp32 (* (ggml_bf16_t * )& buf [i ])); 273 }else if (t -> type == GGML_TYPE_F32 ) { 274tv .push_back (* (float * )& buf [i ]); 275 }else if (t -> type == GGML_TYPE_I64 ) { 276tv .push_back ((float )* (int64_t * )& buf [i ]); 277 }else if (t -> type == GGML_TYPE_I32 ) { 278tv .push_back ((float )* (int32_t * )& buf [i ]); 279 }else if (t -> type == GGML_TYPE_I16 ) { 280tv .push_back ((float )* (int16_t * )& buf [i ]); 281 }else if (t -> type == GGML_TYPE_I8 ) { 282tv .push_back ((float )* (int8_t * )& buf [i ]); 283 }else if (quantized ) { 284tt -> to_float (& buf [i ],vq .data (),bs ); 285tv .insert (tv .end (),vq .begin (),vq .end ()); 286 }else { 287GGML_ABORT ("fatal error" ); 288 } 289 } 290 } 291 } 292 } 293 294return tv ; 295} 296 297// normalized mean squared error = mse(a, b) / mse(a, 0) 298static double nmse (const float * a ,const float * b ,size_t n ) { 299double mse_a_b = 0.0 ; 300double mse_a_0 = 0.0 ; 301 302for (size_t i = 0 ;i < n ;i ++ ) { 303float a_i = a [i ]; 304float b_i = b [i ]; 305 306mse_a_b += (a_i - b_i )* (a_i - b_i ); 307mse_a_0 += a_i * a_i ; 308 } 309 310return mse_a_b /mse_a_0 ; 311} 312 313// difference between 2 sets (Jaccard distance, 0 - no difference, 1 - no overlap) 314template < typename T > 315static double jdst (const T * a ,const T * b ,size_t n ) { 316 std::unordered_map < T ,size_t > set_a ; 317 std::unordered_map < T ,size_t > set_b ; 318 319for (size_t i = 0 ;i < n ;++ i ) { 320set_a [a [i ]]++ ; 321set_b [b [i ]]++ ; 322 } 323 324size_t diff = 0 ; 325 326for (const auto & p :set_a ) { 327const int64_t na = p .second ; 328const int64_t nb = set_b .find (p .first )!= set_b .end () ?set_b .at (p .first ) :0 ; 329 330diff += std::abs (na - nb ); 331 } 332 333for (const auto & p :set_b ) { 334if (set_a .find (p .first )== set_a .end ()) { 335diff += p .second ; 336 } 337 } 338 339return (double )diff / (2 * n ); 340} 341 342// maximum absolute asymmetry between a and b 343// asymmetry: (a - b) / (a + b) 344// This is more stable than relative error if one of the values fluctuates towards zero. 345// n: number of values to compare. 346// expected_vals: optional vector of expected values for a. If expected_vals is not empty, filter out all comparisons where 347// a does not match any of the expected values. Needed for noncontinuous gradients where the numerical calculation can fail. 348static double mean_abs_asymm (const float * a ,const float * b ,const size_t n ,const std::vector < float > & expected_vals ) { 349double sum = 0.0f ; 350 351size_t nvalid = 0 ; 352for (size_t i = 0 ;i < n ;i ++ ) { 353if (!expected_vals .empty ()) { 354bool matches_any = false; 355for (const float & ev :expected_vals ) { 356if (fabsf (a [i ]- ev )< 1e-3f ) { 357matches_any = true; 358break ; 359 } 360 } 361if (!matches_any ) { 362continue ; 363 } 364 } 365 366const float asymm = (a [i ]- b [i ]) / (a [i ]+ b [i ]); 367 368sum += fabsf (asymm ); 369nvalid ++ ; 370 } 371 372return sum /nvalid ; 373} 374 375// utils for printing the variables of the test cases 376 377static std::string var_to_str (const std::string & x ) { 378return x ; 379} 380 381template < typename T > 382static std::string var_to_str (const T & x ) { 383return std::to_string (x ); 384} 385 386template < typename T ,size_t N > 387static std::string var_to_str (const T (& x )[N ]) { 388 std::string s = "[" ; 389for (size_t i = 0 ;i < N ;i ++ ) { 390if (i > 0 ) { 391s += "," ; 392 } 393s += var_to_str (x [i ]); 394 } 395s += "]" ; 396return s ; 397} 398 399template < typename T ,size_t N > 400static std::string var_to_str (const std::array < T ,N > & x ) { 401 std::string s = "[" ; 402for (size_t i = 0 ;i < N ;i ++ ) { 403if (i > 0 ) { 404s += "," ; 405 } 406s += var_to_str (x [i ]); 407 } 408s += "]" ; 409return s ; 410} 411 412static std::string var_to_str (ggml_type type ) { 413return ggml_type_name (type ); 414} 415 416static std::string var_to_str (ggml_prec prec ) { 417return prec == GGML_PREC_F32 ?"f32" :"def" ; 418} 419 420static std::string var_to_str (ggml_op_pool pool ) { 421switch (pool ) { 422case GGML_OP_POOL_AVG :return "avg" ; 423case GGML_OP_POOL_MAX :return "max" ; 424default :return std::to_string (pool ); 425 } 426} 427 428static std::string var_to_str (ggml_scale_mode mode ) { 429 std::string str ; 430switch (mode & 0xFF ) { 431case GGML_SCALE_MODE_NEAREST :str = "nearest" ;break ; 432case GGML_SCALE_MODE_BILINEAR :str = "bilinear" ;break ; 433case GGML_SCALE_MODE_BICUBIC :str = "bicubic" ;break ; 434default :str = std::to_string (mode );break ; 435 } 436if (mode & GGML_SCALE_FLAG_ALIGN_CORNERS ) { 437str += "|align_corners" ; 438 } 439if (mode & GGML_SCALE_FLAG_ANTIALIAS ) { 440str += "|antialias" ; 441 } 442return str ; 443} 444 445#define VAR_TO_STR (x ) (#x "=" + var_to_str(x)) 446 447#define VARS_TO_STR1 (a ) VAR_TO_STR(a) 448#define VARS_TO_STR2 (a ,b ) VAR_TO_STR(a) + "," + VAR_TO_STR(b) 449#define VARS_TO_STR3 (a ,b ,c ) VAR_TO_STR(a) + "," + VARS_TO_STR2(b, c) 450#define VARS_TO_STR4 (a ,b ,c ,d ) VAR_TO_STR(a) + "," + VARS_TO_STR3(b, c, d) 451#define VARS_TO_STR5 (a ,b ,c ,d ,e ) VAR_TO_STR(a) + "," + VARS_TO_STR4(b, c, d, e) 452#define VARS_TO_STR6 (a ,b ,c ,d ,e ,f ) VAR_TO_STR(a) + "," + VARS_TO_STR5(b, c, d, e, f) 453#define VARS_TO_STR7 (a ,b ,c ,d ,e ,f ,g ) VAR_TO_STR(a) + "," + VARS_TO_STR6(b, c, d, e, f, g) 454#define VARS_TO_STR8 (a ,b ,c ,d ,e ,f ,g ,h ) VAR_TO_STR(a) + "," + VARS_TO_STR7(b, c, d, e, f, g, h) 455#define VARS_TO_STR9 (a ,b ,c ,d ,e ,f ,g ,h ,i ) VAR_TO_STR(a) + "," + VARS_TO_STR8(b, c, d, e, f, g, h, i) 456#define VARS_TO_STR10 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ) VAR_TO_STR(a) + "," + VARS_TO_STR9(b, c, d, e, f, g, h, i, j) 457#define VARS_TO_STR11 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ) VAR_TO_STR(a) + "," + VARS_TO_STR10(b, c, d, e, f, g, h, i, j, k) 458#define VARS_TO_STR12 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ) VAR_TO_STR(a) + "," + VARS_TO_STR11(b, c, d, e, f, g, h, i, j, k, l) 459#define VARS_TO_STR13 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ,m ) VAR_TO_STR(a) + "," + VARS_TO_STR12(b, c, d, e, f, g, h, i, j, k, l, m) 460#define VARS_TO_STR14 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ,m ,n ) VAR_TO_STR(a) + "," + VARS_TO_STR13(b, c, d, e, f, g, h, i, j, k, l, m, n) 461#define VARS_TO_STR15 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ,m ,n ,o ) VAR_TO_STR(a) + "," + VARS_TO_STR14(b, c, d, e, f, g, h, i, j, k, l, m, n, o) 462#define VARS_TO_STR16 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ,m ,n ,o ,p ) VAR_TO_STR(a) + "," + VARS_TO_STR15(b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) 463#define VARS_TO_STR17 (a ,b ,c ,d ,e ,f ,g ,h ,i ,j ,k ,l ,m ,n ,o ,p ,q ) VAR_TO_STR(a) + "," + VARS_TO_STR16(b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) 464 465// accept FLT_MAX as infinity 466static bool isinf_or_max (float f ) { 467return std::isinf (f )|| f == FLT_MAX || f == - FLT_MAX ; 468} 469 470static bool ggml_is_view_op (enum ggml_op op ) { 471return op == GGML_OP_VIEW || op == GGML_OP_RESHAPE || op == GGML_OP_PERMUTE || op == GGML_OP_TRANSPOSE ; 472} 473 474static bool backend_has_feature (ggml_backend_t backend ,const char * feature_name ) { 475ggml_backend_dev_t dev = ggml_backend_get_device (backend ); 476ggml_backend_reg_t reg = ggml_backend_dev_backend_reg (dev ); 477 478auto get_features = (ggml_backend_get_features_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_get_features" ); 479if (!get_features ) { 480return false; 481 } 482 483const ggml_backend_feature * features = get_features (reg ); 484if (!features ) { 485return false; 486 } 487 488for (const ggml_backend_feature * f = features ;f -> name ;++ f ) { 489if (strcmp (f -> name ,feature_name )== 0 && strcmp (f -> value ,"1" )== 0 ) { 490return true; 491 } 492 } 493return false; 494} 495 496enum test_mode { 497MODE_TEST , 498MODE_PERF , 499MODE_GRAD , 500MODE_SUPPORT , 501}; 502 503// Output format support similar to llama-bench 504enum output_formats {CONSOLE ,SQL ,CSV }; 505 506static const char * output_format_str (output_formats format ) { 507switch (format ) { 508case CONSOLE : 509return "console" ; 510case SQL : 511return "sql" ; 512case CSV : 513return "csv" ; 514default : 515GGML_ABORT ("invalid output format" ); 516 } 517} 518 519static bool output_format_from_str (const std::string & s ,output_formats & format ) { 520if (s == "console" ) { 521format = CONSOLE ; 522 }else if (s == "sql" ) { 523format = SQL ; 524 }else if (s == "csv" ) { 525format = CSV ; 526 }else { 527return false; 528 } 529return true; 530} 531 532static std::string test_time_now () { 533time_t t = time (NULL ); 534struct tm tm_buf ; 535#ifdef _WIN32 536if (gmtime_s (& tm_buf ,& t )!= 0 ) { 537return "" ; 538 } 539#else 540if (gmtime_r (& t ,& tm_buf )== nullptr ) { 541return "" ; 542 } 543#endif 544char buf [32 ]; 545if (std::strftime (buf ,sizeof (buf ),"%FT%TZ" ,& tm_buf )== 0 ) { 546return "" ; 547 } 548return buf ; 549} 550 551// Test result structure for SQL output 552struct test_result { 553 std::string test_time ; 554 std::string build_commit ; 555 std::string backend_name ; 556 std::string op_name ; 557 std::string op_params ; 558 std::string test_mode ; 559bool supported ; 560bool passed ; 561 std::string error_message ; 562double time_us ; 563double flops ; 564double bandwidth_gb_s ; 565size_t memory_kb ; 566int n_runs ; 567 std::string device_description ; 568 std::string backend_reg_name ; 569 570test_result () { 571// Initialize with default values 572time_us = 0.0 ; 573flops = 0.0 ; 574bandwidth_gb_s = 0.0 ; 575memory_kb = 0 ; 576n_runs = 0 ; 577supported = false; 578passed = false; 579 580test_time = test_time_now (); 581 582// Set build info 583build_commit = ggml_commit (); 584 } 585 586test_result (const std::string & backend_name ,const std::string & op_name ,const std::string & op_params , 587const std::string & test_mode ,bool supported ,bool passed ,const std::string & error_message = "" , 588double time_us = 0.0 ,double flops = 0.0 ,double bandwidth_gb_s = 0.0 ,size_t memory_kb = 0 , 589int n_runs = 0 ,const std::string & device_description = "" ,const std::string & backend_reg_name = "" ) : 590backend_name (backend_name ), 591op_name (op_name ), 592op_params (op_params ), 593test_mode (test_mode ), 594supported (supported ), 595passed (passed ), 596error_message (error_message ), 597time_us (time_us ), 598flops (flops ), 599bandwidth_gb_s (bandwidth_gb_s ), 600memory_kb (memory_kb ), 601n_runs (n_runs ), 602device_description (device_description ), 603backend_reg_name (backend_reg_name ) { 604test_time = test_time_now (); 605 606// Set build info 607build_commit = ggml_commit (); 608 } 609 610static const std::vector < std::string > & get_fields () { 611static const std::vector < std::string > fields = { 612"test_time" ,"build_commit" ,"backend_name" ,"op_name" ,"op_params" ,"test_mode" ,"supported" , 613"passed" ,"error_message" ,"time_us" ,"flops" ,"bandwidth_gb_s" ,"memory_kb" ,"n_runs" , 614"device_description" ,"backend_reg_name" 615 }; 616return fields ; 617 } 618 619enum field_type {STRING ,BOOL ,INT ,FLOAT }; 620 621static field_type get_field_type (const std::string & field ) { 622if (field == "supported" || field == "passed" ) { 623return BOOL ; 624 } 625if (field == "memory_kb" || field == "n_runs" ) { 626return INT ; 627 } 628if (field == "time_us" || field == "flops" || field == "bandwidth_gb_s" ) { 629return FLOAT ; 630 } 631return STRING ; 632 } 633 634 std::vector < std::string > get_values ()const { 635return {test_time , 636build_commit , 637backend_name , 638op_name , 639op_params , 640test_mode , 641 std::to_string (supported ), 642 std::to_string (passed ), 643error_message , 644 std::to_string (time_us ), 645 std::to_string (flops ), 646 std::to_string (bandwidth_gb_s ), 647 std::to_string (memory_kb ), 648 std::to_string (n_runs ), 649device_description , 650backend_reg_name }; 651 } 652}; 653 654// Printer classes for different output formats 655enum class test_status_t {NOT_SUPPORTED ,OK ,FAIL ,SKIPPED }; 656 657struct test_operation_info { 658 std::string op_name ; 659 std::string op_params ; 660 std::string backend_name ; 661test_status_t status = test_status_t::OK ; 662 std::string failure_reason ; 663 664// Additional information fields that were previously in separate structs 665 std::string error_component ; 666 std::string error_details ; 667 668// Gradient info 669int64_t gradient_index = -1 ; 670 std::string gradient_param_name ; 671float gradient_value = 0.0f ; 672 673// MAA error info 674double maa_error = 0.0 ; 675double maa_threshold = 0.0 ; 676 677// Flags for different types of information 678bool has_error = false; 679bool has_gradient_info = false; 680bool has_maa_error = false; 681bool is_compare_failure = false; 682bool is_large_tensor_skip = false; 683 684test_operation_info ()= default ; 685 686test_operation_info (const std::string & op_name ,const std::string & op_params ,const std::string & backend_name , 687test_status_t status = test_status_t::OK ,const std::string & failure_reason = "" ) : 688op_name (op_name ), 689op_params (op_params ), 690backend_name (backend_name ), 691status (status ), 692failure_reason (failure_reason ) {} 693 694// Set error information 695void set_error (const std::string & component ,const std::string & details ) { 696has_error = true; 697error_component = component ; 698error_details = details ; 699if (status == test_status_t::OK ) { 700status = test_status_t::FAIL ; 701 } 702 } 703 704// Set gradient information 705void set_gradient_info (int64_t index ,const std::string & param_name ,float value ) { 706has_gradient_info = true; 707gradient_index = index ; 708gradient_param_name = param_name ; 709gradient_value = value ; 710if (status == test_status_t::OK ) { 711status = test_status_t::FAIL ; 712 } 713 } 714 715// Set MAA error information 716void set_maa_error (double error ,double threshold ) { 717has_maa_error = true; 718maa_error = error ; 719maa_threshold = threshold ; 720if (status == test_status_t::OK ) { 721status = test_status_t::FAIL ; 722 } 723 } 724 725// Set compare failure 726void set_compare_failure () { 727is_compare_failure = true; 728if (status == test_status_t::OK ) { 729status = test_status_t::FAIL ; 730 } 731 } 732 733// Set large tensor skip 734void set_large_tensor_skip () {is_large_tensor_skip = true; } 735}; 736 737struct test_summary_info { 738size_t tests_passed ; 739size_t tests_total ; 740bool is_backend_summary = false;// true for backend summary, false for test summary 741 742test_summary_info ()= default ; 743 744test_summary_info (size_t tests_passed ,size_t tests_total ,bool is_backend_summary = false) : 745tests_passed (tests_passed ), 746tests_total (tests_total ), 747is_backend_summary (is_backend_summary ) {} 748}; 749 750struct testing_start_info { 751size_t device_count ; 752 753testing_start_info ()= default ; 754 755testing_start_info (size_t device_count ) :device_count (device_count ) {} 756}; 757 758struct backend_init_info { 759size_t device_index ; 760size_t total_devices ; 761 std::string device_name ; 762bool skipped = false; 763 std::string skip_reason ; 764 std::string description ; 765size_t memory_total_mb = 0 ; 766size_t memory_free_mb = 0 ; 767bool has_memory_info = false; 768 769backend_init_info ()= default ; 770 771backend_init_info (size_t device_index ,size_t total_devices ,const std::string & device_name ,bool skipped = false, 772const std::string & skip_reason = "" ,const std::string & description = "" , 773size_t memory_total_mb = 0 ,size_t memory_free_mb = 0 ,bool has_memory_info = false) : 774device_index (device_index ), 775total_devices (total_devices ), 776device_name (device_name ), 777skipped (skipped ), 778skip_reason (skip_reason ), 779description (description ), 780memory_total_mb (memory_total_mb ), 781memory_free_mb (memory_free_mb ), 782has_memory_info (has_memory_info ) {} 783}; 784 785struct backend_status_info { 786 std::string backend_name ; 787test_status_t status ; 788 789backend_status_info ()= default ; 790 791backend_status_info (const std::string & backend_name ,test_status_t status ) : 792backend_name (backend_name ), 793status (status ) {} 794}; 795 796struct overall_summary_info { 797size_t backends_passed ; 798size_t backends_total ; 799bool all_passed ; 800 801overall_summary_info ()= default ; 802 803overall_summary_info (size_t backends_passed ,size_t backends_total ,bool all_passed ) : 804backends_passed (backends_passed ), 805backends_total (backends_total ), 806all_passed (all_passed ) {} 807}; 808 809struct printer { 810virtual ~printer () {} 811 812FILE * fout = stdout ; 813 814virtual void print_header () {} 815 816virtual void print_test_result (const test_result & result )= 0 ; 817 818virtual void print_footer () {} 819 820virtual void print_operation (const test_operation_info & info ) { (void )info ; } 821 822virtual void print_summary (const test_summary_info & info ) { (void )info ; } 823 824virtual void print_testing_start (const testing_start_info & info ) { (void )info ; } 825 826virtual void print_backend_init (const backend_init_info & info ) { (void )info ; } 827 828virtual void print_backend_status (const backend_status_info & info ) { (void )info ; } 829 830virtual void print_overall_summary (const overall_summary_info & info ) { (void )info ; } 831 832virtual void print_failed_tests (const std::vector < std::string > & failed_tests ) { (void )failed_tests ; } 833}; 834 835struct console_printer :public printer { 836void print_test_result (const test_result & result )override { 837if (result .test_mode == "test" ) { 838print_test_console (result ); 839 }else if (result .test_mode == "perf" ) { 840print_perf_console (result ); 841 }else if (result .test_mode == "support" ) { 842print_support_console (result ); 843 } 844 } 845 846void print_operation (const test_operation_info & info )override { 847printf (" %s(%s): " ,info .op_name .c_str (),info .op_params .c_str ()); 848fflush (stdout ); 849 850// Handle large tensor skip first 851if (info .is_large_tensor_skip ) { 852printf ("skipping large tensors for speed \n" ); 853return ; 854 } 855 856// Handle not supported status 857if (info .status == test_status_t::NOT_SUPPORTED ) { 858if (!info .failure_reason .empty ()) { 859printf ("not supported [%s]\n" ,info .failure_reason .c_str ()); 860 }else { 861printf ("not supported [%s]\n" ,info .backend_name .c_str ()); 862 } 863return ; 864 } 865 866// Handle errors and additional information 867if (info .has_error ) { 868if (info .error_component == "allocation" ) { 869fprintf (stderr ,"failed to allocate tensors [%s] " ,info .backend_name .c_str ()); 870 }else if (info .error_component == "backend" ) { 871fprintf (stderr ," Failed to initialize %s backend\n" ,info .backend_name .c_str ()); 872 }else { 873fprintf (stderr ,"Error in %s: %s\n" ,info .error_component .c_str (),info .error_details .c_str ()); 874 } 875 } 876 877// Handle gradient info 878if (info .has_gradient_info ) { 879printf ("[%s] nonfinite gradient at index %" PRId64 " (%s=%f) " ,info .op_name .c_str (),info .gradient_index , 880info .gradient_param_name .c_str (),info .gradient_value ); 881 } 882 883// Handle MAA error 884if (info .has_maa_error ) { 885printf ("[%s] MAA = %.9f > %.9f " ,info .op_name .c_str (),info .maa_error ,info .maa_threshold ); 886 } 887 888// Handle compare failure 889if (info .is_compare_failure ) { 890printf ("compare failed " ); 891 } 892 893// Print final status 894if (info .status == test_status_t::OK ) { 895printf ("\033[1;32mOK\033[0m\n" ); 896 }else { 897printf ("\033[1;31mFAIL\033[0m\n" ); 898 } 899 } 900 901void print_summary (const test_summary_info & info )override { 902if (info .is_backend_summary ) { 903printf ("%zu/%zu backends passed\n" ,info .tests_passed ,info .tests_total ); 904 }else { 905printf (" %zu/%zu tests passed\n" ,info .tests_passed ,info .tests_total ); 906 } 907 } 908 909void print_backend_status (const backend_status_info & info )override { 910printf (" Backend %s: " ,info .backend_name .c_str ()); 911if (info .status == test_status_t::OK ) { 912printf ("\033[1;32mOK\033[0m\n" ); 913 }else { 914printf ("\033[1;31mFAIL\033[0m\n" ); 915 } 916 } 917 918void print_testing_start (const testing_start_info & info )override { 919printf ("Testing %zu devices\n\n" ,info .device_count ); 920 } 921 922void print_backend_init (const backend_init_info & info )override { 923printf ("Backend %zu/%zu: %s\n" ,info .device_index + 1 ,info .total_devices ,info .device_name .c_str ()); 924 925if (info .skipped ) { 926printf (" %s\n" ,info .skip_reason .c_str ()); 927return ; 928 } 929 930if (!info .description .empty ()) { 931printf (" Device description: %s\n" ,info .description .c_str ()); 932 } 933 934if (info .has_memory_info ) { 935printf (" Device memory: %zu MB (%zu MB free)\n" ,info .memory_total_mb ,info .memory_free_mb ); 936 } 937 938printf ("\n" ); 939 } 940 941void print_overall_summary (const overall_summary_info & info )override { 942printf ("%zu/%zu backends passed\n" ,info .backends_passed ,info .backends_total ); 943if (info .all_passed ) { 944printf ("\033[1;32mOK\033[0m\n" ); 945 }else { 946printf ("\033[1;31mFAIL\033[0m\n" ); 947 } 948 } 949 950void print_failed_tests (const std::vector < std::string > & failed_tests )override { 951if (failed_tests .empty ()) { 952return ; 953 } 954 955printf ("\nFailing tests:\n" ); 956for (const auto & test_name :failed_tests ) { 957printf (" %s\n" ,test_name .c_str ()); 958 } 959 } 960 961private : 962void print_test_console (const test_result & result ) { 963printf (" %s(%s): " ,result .op_name .c_str (),result .op_params .c_str ()); 964fflush (stdout ); 965 966if (!result .supported ) { 967printf ("not supported [%s] " ,result .backend_name .c_str ()); 968printf ("\n" ); 969return ; 970 } 971 972if (result .passed ) { 973printf ("\033[1;32mOK\033[0m\n" ); 974 }else { 975printf ("\033[1;31mFAIL\033[0m\n" ); 976 } 977 } 978 979void print_perf_console (const test_result & result ) { 980int len = printf (" %s(%s): " ,result .op_name .c_str (),result .op_params .c_str ()); 981fflush (stdout ); 982 983if (!result .supported ) { 984printf ("not supported\n" ); 985return ; 986 } 987 988// align while also leaving some margin for variations in parameters 989int align = 8 ; 990int last = (len + align - 1 ) /align * align ; 991if (last - len < 5 ) { 992last += align ; 993 } 994printf ("%*s" ,last - len ,"" ); 995 996printf (" %8d runs - %8.2f us/run - " ,result .n_runs ,result .time_us ); 997 998if (result .flops > 0 ) { 999auto format_flops = [](double flops )-> std::string { 1000char buf [256 ]; 1001if (flops >=1e12 ) { 1002snprintf (buf ,sizeof (buf ),"%6.2f TFLOP" ,flops /1e12 ); 1003 }else if (flops >=1e9 ) { 1004snprintf (buf ,sizeof (buf ),"%6.2f GFLOP" ,flops /1e9 ); 1005 }else if (flops >=1e6 ) { 1006snprintf (buf ,sizeof (buf ),"%6.2f MFLOP" ,flops /1e6 ); 1007 }else { 1008snprintf (buf ,sizeof (buf ),"%6.2f kFLOP" ,flops /1e3 ); 1009 } 1010return buf ; 1011 }; 1012uint64_t op_flops_per_run = result .flops * result .time_us /1e6 ; 1013printf ("%s/run - \033[1;34m%sS\033[0m" ,format_flops (op_flops_per_run ).c_str (), 1014format_flops (result .flops ).c_str ()); 1015 }else { 1016printf ("%8zu kB/run - \033[1;34m%7.2f GB/s\033[0m" ,result .memory_kb ,result .bandwidth_gb_s ); 1017 } 1018printf ("\n" ); 1019 } 1020 1021void print_support_console (const test_result & result ) { 1022printf (" %s(%s): " ,result .op_name .c_str (),result .op_params .c_str ()); 1023fflush (stdout ); 1024 1025if (result .supported ) { 1026printf ("\033[1;32mSUPPORTED\033[0m\n" ); 1027 }else { 1028printf ("\033[1;31mNOT SUPPORTED\033[0m\n" ); 1029 } 1030 } 1031}; 1032 1033struct sql_printer :public printer { 1034static std::string get_sql_field_type (const std::string & field ) { 1035switch (test_result::get_field_type (field )) { 1036case test_result::STRING : 1037return "TEXT" ; 1038case test_result::BOOL : 1039case test_result::INT : 1040return "INTEGER" ; 1041case test_result::FLOAT : 1042return "REAL" ; 1043default : 1044GGML_ABORT ("invalid field type" ); 1045 } 1046 } 1047 1048void print_header ()override { 1049 std::vector < std::string > fields = test_result::get_fields (); 1050fprintf (fout ,"CREATE TABLE IF NOT EXISTS test_backend_ops (\n" ); 1051for (size_t i = 0 ;i < fields .size ();i ++ ) { 1052fprintf (fout ," %s %s%s\n" ,fields [i ].c_str (),get_sql_field_type (fields [i ]).c_str (), 1053i < fields .size ()- 1 ?"," :"" ); 1054 } 1055fprintf (fout ,");\n\n" ); 1056 } 1057 1058void print_test_result (const test_result & result )override { 1059fprintf (fout ,"INSERT INTO test_backend_ops (" ); 1060 std::vector < std::string > fields = test_result::get_fields (); 1061for (size_t i = 0 ;i < fields .size ();i ++ ) { 1062fprintf (fout ,"%s%s" ,fields [i ].c_str (),i < fields .size ()- 1 ?", " :"" ); 1063 } 1064fprintf (fout ,") VALUES (" ); 1065 std::vector < std::string > values = result .get_values (); 1066for (size_t i = 0 ;i < values .size ();i ++ ) { 1067fprintf (fout ,"'%s'%s" ,values [i ].c_str (),i < values .size ()- 1 ?", " :"" ); 1068 } 1069fprintf (fout ,");\n" ); 1070 } 1071}; 1072 1073struct csv_printer :public printer { 1074void print_header ()override { 1075 1076 std::vector < std::string > fields = test_result::get_fields (); 1077 std::vector < std::string > fields_csv = get_fields_csv (); 1078for (size_t i = 0 ;i < fields .size ();i ++ ) { 1079if (std::find (std::begin (fields_csv ), std::end (fields_csv ),fields [i ])== std::end (fields_csv )) { 1080continue ; 1081 } 1082printf ("\"%s\"%s" ,fields [i ].c_str (),i < fields .size ()- 1 ?"," :"" ); 1083 } 1084printf ("\n" ); 1085 } 1086 1087void print_test_result (const test_result & result )override { 1088 1089 std::vector < std::string > values = result .get_values (); 1090 std::vector < std::string > fields = test_result::get_fields (); 1091 std::vector < std::string > fields_csv = get_fields_csv (); 1092 1093for (size_t i = 0 ;i < values .size ();i ++ ) { 1094 1095if (std::find (std::begin (fields_csv ), std::end (fields_csv ),fields [i ])== std::end (fields_csv )) { 1096continue ; 1097 } 1098 1099// Escape quotes and wrap in quotes for CSV 1100 std::string escaped_value = values [i ]; 1101size_t pos = 0 ; 1102while ((pos = escaped_value .find ("\"" ,pos ))!= std::string::npos ) { 1103escaped_value .replace (pos ,1 ,"\"\"" ); 1104pos += 2 ; 1105 } 1106printf ("\"%s\"%s" ,escaped_value .c_str (),i < values .size ()- 1 ?"," :"" ); 1107 } 1108printf ("\n" ); 1109 } 1110 1111static std::vector < std::string > get_fields_csv () { 1112return { 1113"op_name" , 1114"op_params" , 1115"supported" , 1116"error_message" , 1117"test_mode" , 1118"backend_reg_name" , 1119"backend_name" , 1120 }; 1121 } 1122 1123}; 1124 1125static std::unique_ptr < printer > create_printer (output_formats format ) { 1126switch (format ) { 1127case CONSOLE : 1128return std::make_unique < console_printer > (); 1129case SQL : 1130return std::make_unique < sql_printer > (); 1131case CSV : 1132return std::make_unique < csv_printer > (); 1133 } 1134GGML_ABORT ("invalid output format" ); 1135} 1136 1137static std::mutex g_test_output_mutex ; 1138 1139static void print_test_result_locked (printer * output_printer ,const test_result & result ) { 1140if (output_printer == nullptr ) { 1141return ; 1142 } 1143 1144 std::lock_guard < std::mutex > guard (g_test_output_mutex ); 1145output_printer -> print_test_result (result ); 1146} 1147 1148struct test_case { 1149virtual ~test_case () {} 1150 1151virtual std::string op_desc (ggml_tensor * t ) { 1152return ggml_op_desc (t ); 1153 } 1154 1155virtual std::string vars () { 1156return "" ; 1157 } 1158 1159virtual ggml_tensor * build_graph (ggml_context * ctx )= 0 ; 1160virtual ggml_tensor * build_graph (ggml_context * ctx ,ggml_context * ctx_weights ) { 1161GGML_UNUSED (ctx_weights ); 1162return build_graph (ctx ); 1163 } 1164 1165virtual double max_nmse_err () { 1166return 1e-7 ; 1167 } 1168 1169virtual double max_nmse_err (ggml_backend_t backend ) { 1170ggml_backend_reg_t reg = ggml_backend_dev_backend_reg (ggml_backend_get_device (backend )); 1171// See https://github.com/ggml-org/llama.cpp/pull/22976 for explanation. 1172if (contains_f16 && strcmp (ggml_backend_reg_name (reg ),"WebGPU" )== 0 ) { 1173return std::max (max_nmse_err (),1e-6 ); 1174 } 1175return max_nmse_err (); 1176 } 1177 1178virtual double max_maa_err () { 1179return 1e-4 ; 1180 } 1181 1182virtual double max_err () { 1183return max_nmse_err (); 1184 } 1185 1186virtual double max_err (ggml_backend_t backend ) { 1187return max_nmse_err (backend ); 1188 } 1189 1190virtual double err (const float * a ,const float * b ,size_t n ) { 1191return nmse (a ,b ,n ); 1192 } 1193 1194virtual float grad_eps () { 1195return 1e-1f ; 1196 } 1197 1198// If false, estimate gradient with 2 points, neglects 3rd order derivative and higher. 1199// If true, estimate gradient with 4 points, neglects 5th order derivative and higher. 1200virtual bool grad_precise () { 1201return false; 1202 } 1203 1204// Skip gradient checks if total number of gradients to be checked is larger than this (to speed up the tests). 1205virtual int64_t grad_nmax () { 1206return 10000 ; 1207 } 1208 1209// No effect if empty. 1210// If not empty, skip all gradient checks where the numerical result does not match any of the values. 1211// Needed for dealing with noncontinuous gradients (e.g. ReLU) where estimation using finite differences is unreliable. 1212virtual std::vector < float > grad_expect () { 1213return {}; 1214 } 1215 1216virtual void initialize_tensors (ggml_context * ctx ) { 1217for (ggml_tensor * t = ggml_get_first_tensor (ctx );t != nullptr ;t = ggml_get_next_tensor (ctx ,t )) { 1218init_tensor_uniform (t ); 1219 } 1220 } 1221 1222// re-draw data-dependent inputs between timed perf iterations 1223virtual void reinit_perf_iter (ggml_context * ctx ) { 1224GGML_UNUSED (ctx ); 1225 } 1226 1227virtual size_t op_size (ggml_tensor * t ) { 1228size_t size = ggml_nbytes (t ); 1229// add source tensors 1230for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 1231if (t -> src [i ]!= NULL ) { 1232size += ggml_nbytes (t -> src [i ]); 1233 } 1234 } 1235return size ; 1236 } 1237 1238virtual uint64_t op_flops (ggml_tensor * t ) { 1239GGML_UNUSED (t ); 1240return 0 ; 1241 } 1242 1243virtual bool run_whole_graph () {return false; } 1244virtual std::vector < ggml_tensor *> fusion_test_nodes () {return {}; } 1245virtual bool use_weight_context () {return false; } 1246 1247ggml_cgraph * gf = nullptr ; 1248ggml_cgraph * gb = nullptr ; 1249 1250static const int sentinel_size = 1024 ; 1251 1252test_mode mode ; 1253 1254 std::vector < ggml_tensor *> sentinels ; 1255 1256 std::string current_op_name ; 1257bool contains_f16 = false; 1258 1259// Used by the WebGPU backend to relax error thresholds on ops on f16 tensors 1260void check_for_f16_tensor (ggml_context * ctx ) { 1261contains_f16 = false; 1262for (ggml_tensor * t = ggml_get_first_tensor (ctx );t != nullptr ;t = ggml_get_next_tensor (ctx ,t )) { 1263if (t -> type == GGML_TYPE_F16 ) { 1264contains_f16 = true; 1265break ; 1266 } 1267 } 1268 } 1269 1270void add_sentinel (ggml_context * ctx ) { 1271if (mode == MODE_PERF || mode == MODE_GRAD || mode == MODE_SUPPORT ) { 1272return ; 1273 } 1274ggml_tensor * sentinel = ::ggml_new_tensor_1d (ctx ,GGML_TYPE_F32 ,sentinel_size ); 1275ggml_format_name (sentinel ,"sent_%zu" ,sentinels .size ()); 1276sentinels .push_back (sentinel ); 1277 } 1278 1279// hijack ggml_new_tensor to add sentinels after each tensor to check for overflows in the backend 1280 1281ggml_tensor * ggml_new_tensor (ggml_context * ctx ,ggml_type type ,int n_dims ,const int64_t * ne ) { 1282ggml_tensor * t = ::ggml_new_tensor (ctx ,type ,n_dims ,ne ); 1283add_sentinel (ctx ); 1284return t ; 1285 } 1286 1287ggml_tensor * ggml_new_tensor_1d (ggml_context * ctx ,ggml_type type ,int64_t ne0 ) { 1288ggml_tensor * t = ::ggml_new_tensor_1d (ctx ,type ,ne0 ); 1289add_sentinel (ctx ); 1290return t ; 1291 } 1292 1293ggml_tensor * ggml_new_tensor_2d (ggml_context * ctx ,ggml_type type ,int64_t ne0 ,int64_t ne1 ) { 1294ggml_tensor * t = ::ggml_new_tensor_2d (ctx ,type ,ne0 ,ne1 ); 1295add_sentinel (ctx ); 1296return t ; 1297 } 1298 1299ggml_tensor * ggml_new_tensor_3d (ggml_context * ctx ,ggml_type type ,int64_t ne0 ,int64_t ne1 ,int64_t ne2 ) { 1300ggml_tensor * t = ::ggml_new_tensor_3d (ctx ,type ,ne0 ,ne1 ,ne2 ); 1301add_sentinel (ctx ); 1302return t ; 1303 } 1304 1305ggml_tensor * ggml_new_tensor_4d (ggml_context * ctx ,ggml_type type ,int64_t ne0 ,int64_t ne1 ,int64_t ne2 ,int64_t ne3 ) { 1306ggml_tensor * t = ::ggml_new_tensor_4d (ctx ,type ,ne0 ,ne1 ,ne2 ,ne3 ); 1307add_sentinel (ctx ); 1308return t ; 1309 } 1310 1311// Checks an op against the test filter, which is a comma separated list of OP names or specific variations 1312bool matches_filter (ggml_tensor * op ,const char * op_names_filter ) { 1313if (op_names_filter ) { 1314const auto op_name = op_desc (op ); 1315const auto op_full_name = op_name + "(" + vars ()+ ")" ; 1316 std::string_view filter (op_names_filter ); 1317while (!filter .empty ()) { 1318auto comma_pos = filter .find_first_of (',' ); 1319const auto lparen_pos = filter .find_first_of ('(' ); 1320if (lparen_pos < comma_pos ) { 1321auto rparen_pos = filter .find_first_of (')' ); 1322comma_pos = filter .find_first_of (',' ,rparen_pos ); 1323const auto op_filter = filter .substr (0 ,comma_pos ); 1324if (op_filter == op_full_name ) { 1325return true; 1326 } 1327 }else { 1328const auto op_filter = filter .substr (0 ,comma_pos ); 1329if (op_filter == op_name ) { 1330return true; 1331 } 1332 } 1333filter = comma_pos != std::string_view::npos ?filter .substr (comma_pos + 1 ) :"" ; 1334 } 1335return false; 1336 }else { 1337return true; 1338 } 1339 } 1340 1341test_status_t eval (ggml_backend_t backend1 , 1342ggml_backend_t backend2 , 1343const char * op_names_filter , 1344printer * output_printer ) { 1345mode = MODE_TEST ; 1346 1347ggml_init_params params = { 1348/* .mem_size = */ ggml_tensor_overhead ()* 128 + ggml_graph_overhead (), 1349/* .mem_base = */ NULL , 1350/* .no_alloc = */ true, 1351 }; 1352const bool use_weights = use_weight_context (); 1353 1354ggml_context_ptr ctx (ggml_init (params )); 1355GGML_ASSERT (ctx ); 1356ggml_context_ptr ctx_weights (use_weights ?ggml_init (params ) :nullptr ); 1357GGML_ASSERT (!use_weights || ctx_weights ); 1358 1359gf = ggml_new_graph (ctx .get ()); 1360 1361// pre-graph sentinel 1362add_sentinel (ctx .get ()); 1363if (ctx_weights ) { 1364add_sentinel (ctx_weights .get ()); 1365 } 1366 1367ggml_tensor * out = build_graph (ctx .get (),ctx_weights .get ()); 1368current_op_name = op_desc (out ); 1369check_for_f16_tensor (ctx .get ()); 1370 1371if (!matches_filter (out ,op_names_filter )) { 1372//printf(" %s: skipping\n", op_desc(out).c_str()); 1373return test_status_t::SKIPPED ; 1374 } 1375 1376// check if the backends support the ops 1377bool supported = true; 1378 std::string unsupported_str ; 1379for (ggml_backend_t backend : {backend1 ,backend2 }) { 1380for (ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != NULL ;t = ggml_get_next_tensor (ctx .get (),t )) { 1381if (!ggml_backend_supports_op (backend ,t )) { 1382supported = false; 1383if (unsupported_str .empty ()) { 1384unsupported_str = std::string (ggml_backend_name (backend )); 1385 }else { 1386unsupported_str += ", " + std::string (ggml_backend_name (backend )); 1387 } 1388 } 1389 } 1390 } 1391 1392if (!supported ) { 1393test_result result (unsupported_str ,current_op_name ,vars (),"test" , 1394 false, false,"not supported" ); 1395 1396print_test_result_locked (output_printer ,result ); 1397 1398return test_status_t::NOT_SUPPORTED ; 1399 } 1400 1401// post-graph sentinel 1402add_sentinel (ctx .get ()); 1403if (ctx_weights ) { 1404add_sentinel (ctx_weights .get ()); 1405 } 1406 1407ggml_backend_buffer_ptr buf_weights (nullptr ); 1408if (ctx_weights ) { 1409buf_weights .reset (ggml_backend_alloc_ctx_tensors (ctx_weights .get (),backend1 )); 1410if (buf_weights == NULL ) { 1411printf ("failed to allocate weight tensors [%s] " ,ggml_backend_name (backend1 )); 1412return test_status_t::FAIL ; 1413 } 1414ggml_backend_buffer_set_usage (buf_weights .get (),GGML_BACKEND_BUFFER_USAGE_WEIGHTS ); 1415 } 1416 1417// allocate 1418ggml_backend_buffer_ptr buf (ggml_backend_alloc_ctx_tensors (ctx .get (),backend1 )); 1419 1420if (buf == NULL ) { 1421printf ("failed to allocate tensors [%s] " ,ggml_backend_name (backend1 )); 1422return test_status_t::FAIL ; 1423 } 1424 1425// build graph 1426ggml_build_forward_expand (gf ,out ); 1427 1428// add sentinels as graph nodes so that they are checked in the callback 1429for (ggml_tensor * sentinel :sentinels ) { 1430ggml_graph_add_node (gf ,sentinel ); 1431 } 1432 1433// randomize tensors 1434initialize_tensors (ctx .get ()); 1435if (ctx_weights ) { 1436initialize_tensors (ctx_weights .get ()); 1437 } 1438 1439// compare 1440struct callback_userdata { 1441bool ok ; 1442test_case * tc ; 1443ggml_backend_t backend1 ; 1444ggml_backend_t backend2 ; 1445 }; 1446 1447callback_userdata ud { 1448 true, 1449this , 1450backend1 , 1451backend2 , 1452 }; 1453 1454auto callback = [](int index ,ggml_tensor * t1 ,ggml_tensor * t2 ,void * user_data )-> bool { 1455callback_userdata * ud = (callback_userdata * )user_data ; 1456const char * bn1 = ggml_backend_name (ud -> backend1 ); 1457const char * bn2 = ggml_backend_name (ud -> backend2 ); 1458 1459if (t1 -> op == GGML_OP_NONE ) { 1460// sentinels must be unchanged 1461 std::vector < uint8_t > t1_data (ggml_nbytes (t1 )); 1462 std::vector < uint8_t > t2_data (ggml_nbytes (t2 )); 1463ggml_backend_tensor_get (t1 ,t1_data .data (),0 ,ggml_nbytes (t1 )); 1464ggml_backend_tensor_get (t2 ,t2_data .data (),0 ,ggml_nbytes (t2 )); 1465 1466if (memcmp (t1_data .data (),t2_data .data (),ggml_nbytes (t1 ))!= 0 ) { 1467printf ("sentinel mismatch: %s " ,t1 -> name ); 1468ud -> ok = false; 1469return true; 1470 } 1471 } 1472 1473 std::vector < float > f1 = tensor_to_float (t1 ); 1474 std::vector < float > f2 = tensor_to_float (t2 ); 1475 1476for (size_t i = 0 ;i < f1 .size ();i ++ ) { 1477// check for nans 1478if (std::isnan (f1 [i ])|| std::isnan (f2 [i ])) { 1479printf ("[%s] NaN at index %zu (%s=%f %s=%f) " ,ggml_op_desc (t1 ),i ,bn1 ,f1 [i ],bn2 ,f2 [i ]); 1480ud -> ok = false; 1481return true; 1482 } 1483// check for infs: both must be inf of the same sign, or both must be finite 1484if (isinf_or_max (f1 [i ])|| isinf_or_max (f2 [i ])) { 1485if (isinf_or_max (f1 [i ])&& isinf_or_max (f2 [i ])) { 1486if (std::signbit (f1 [i ])!= std::signbit (f2 [i ])) { 1487printf ("[%s] inf sign mismatch: %s=%f %s=%f " ,ggml_op_desc (t1 ),bn1 ,f1 [i ],bn2 ,f2 [i ]); 1488ud -> ok = false; 1489return true; 1490 } 1491 }else { 1492printf ("[%s] inf mismatch: %s=%f %s=%f " ,ggml_op_desc (t1 ),bn1 ,f1 [i ],bn2 ,f2 [i ]); 1493ud -> ok = false; 1494return true; 1495 } 1496 } 1497 } 1498 1499double err = ud -> tc -> err (f1 .data (),f2 .data (),f1 .size ()); 1500if (err > ud -> tc -> max_err (ud -> backend1 )) { 1501printf ("[%s] ERR = %.9f > %.9f " ,ggml_op_desc (t1 ),err ,ud -> tc -> max_err (ud -> backend1 )); 1502//for (int i = 0; i < (int) f1.size(); i++) { 1503// printf("%5d %9.6f %9.6f, diff = %9.6f\n", i, f1[i], f2[i], f1[i] - f2[i]); 1504//} 1505//printf("\n"); 1506//exit(1); 1507ud -> ok = false; 1508 } 1509return true; 1510 1511GGML_UNUSED (index ); 1512 }; 1513 1514 std::vector < ggml_tensor *> fused_nodes_to_verify = fusion_test_nodes (); 1515if (fused_nodes_to_verify .size ()== 0 && run_whole_graph ()) { 1516fused_nodes_to_verify .push_back (out ); 1517 } 1518const bool cmp_ok = ggml_backend_compare_graph_backend (backend1 ,backend2 ,gf ,callback ,& ud , 1519run_whole_graph () ?fused_nodes_to_verify .data () :nullptr , 1520fused_nodes_to_verify .size ()); 1521 1522// Create test result 1523bool test_passed = ud .ok && cmp_ok ; 1524 std::string error_msg = test_passed ?"" : (!cmp_ok ?"compare failed" :"test failed" ); 1525test_result result (ggml_backend_name (backend1 ),current_op_name ,vars (),"test" ,supported ,test_passed , 1526error_msg ); 1527 1528print_test_result_locked (output_printer ,result ); 1529 1530return test_passed ? test_status_t::OK : test_status_t::FAIL ; 1531 } 1532 1533bool eval_perf (ggml_backend_t backend ,const char * op_names_filter ,printer * output_printer ) { 1534mode = MODE_PERF ; 1535 1536static const size_t graph_nodes = 8192 ; 1537 1538ggml_init_params params = { 1539/* .mem_size = */ ggml_tensor_overhead ()* 128 + ggml_graph_overhead_custom (graph_nodes , false), 1540/* .mem_base = */ NULL , 1541/* .no_alloc = */ true, 1542 }; 1543const bool use_weights = use_weight_context (); 1544 1545ggml_context_ptr ctx (ggml_init (params ));// smart ptr 1546GGML_ASSERT (ctx ); 1547ggml_context_ptr ctx_weights (use_weights ?ggml_init (params ) :nullptr ); 1548GGML_ASSERT (!use_weights || ctx_weights ); 1549 1550ggml_tensor * out = build_graph (ctx .get (),ctx_weights .get ()); 1551current_op_name = op_desc (out ); 1552if (!matches_filter (out ,op_names_filter )) { 1553//printf(" %s: skipping\n", op_desc(out).c_str()); 1554return true; 1555 } 1556 1557if (!ggml_backend_supports_op (backend ,out )) { 1558// Create test result for unsupported performance test 1559test_result result (ggml_backend_name (backend ),current_op_name ,vars (),"perf" , false, false, 1560"not supported" ); 1561 1562output_printer -> print_test_result (result ); 1563 1564return true; 1565 } 1566 1567ggml_backend_buffer_ptr buf_weights (nullptr ); 1568if (ctx_weights ) { 1569buf_weights .reset (ggml_backend_alloc_ctx_tensors (ctx_weights .get (),backend )); 1570if (buf_weights == NULL ) { 1571printf ("failed to allocate weight tensors\n" ); 1572return false; 1573 } 1574ggml_backend_buffer_set_usage (buf_weights .get (),GGML_BACKEND_BUFFER_USAGE_WEIGHTS ); 1575 } 1576 1577// allocate 1578ggml_backend_buffer_ptr buf (ggml_backend_alloc_ctx_tensors (ctx .get (),backend ));// smart ptr 1579 1580if (buf == NULL ) { 1581printf ("failed to allocate tensors\n" ); 1582return false; 1583 } 1584 1585// randomize tensors 1586initialize_tensors (ctx .get ()); 1587if (ctx_weights ) { 1588initialize_tensors (ctx_weights .get ()); 1589 } 1590 1591// build graph 1592ggml_cgraph * gf = ggml_new_graph_custom (ctx .get (),graph_nodes , false); 1593ggml_build_forward_expand (gf ,out ); 1594 1595// warmup run 1596ggml_status status = ggml_backend_graph_compute (backend ,gf ); 1597if (status != GGML_STATUS_SUCCESS ) { 1598fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1599return false; 1600 } 1601 1602// determine number of runs 1603int n_runs ; 1604bool is_cpu = ggml_backend_dev_type (ggml_backend_get_device (backend ))== GGML_BACKEND_DEVICE_TYPE_CPU ; 1605if (op_flops (out )> 0 ) { 1606// based on flops 1607const uint64_t GFLOP = 1000 * 1000 * 1000 ; 1608const uint64_t target_flops_cpu = 8ULL * GFLOP ; 1609const uint64_t target_flops_gpu = 100ULL * GFLOP ; 1610uint64_t target_flops = is_cpu ?target_flops_cpu :target_flops_gpu ; 1611n_runs = (int )std::min < int64_t > (ggml_graph_size (gf )- ggml_graph_n_nodes (gf ),target_flops /op_flops (out ))+ 1 ; 1612 }else { 1613// based on memory size 1614const size_t GB = 1ULL <<30 ; 1615const size_t target_size_cpu = 8 * GB ; 1616const size_t target_size_gpu = 32 * GB ; 1617size_t target_size = is_cpu ?target_size_cpu :target_size_gpu ; 1618n_runs = (int )std::min < int64_t > (ggml_graph_size (gf )- ggml_graph_n_nodes (gf ),target_size /op_size (out ))+ 1 ; 1619 } 1620 1621// duplicate the op 1622for (int i = 1 ;i < n_runs ;i ++ ) { 1623ggml_graph_add_node (gf ,out ); 1624 } 1625 1626// calculate memory 1627size_t mem = n_runs * op_size (out ); 1628auto tensor_op_size = [](ggml_tensor * t ) { 1629size_t size = ggml_nbytes (t ); 1630// add source tensors 1631for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 1632if (t -> src [i ]!= NULL ) { 1633size += ggml_nbytes (t -> src [i ]); 1634 } 1635 } 1636return size ; 1637 }; 1638for (int i = 0 ;i < ggml_graph_n_nodes (gf );++ i ) { 1639if (ggml_is_view_op (ggml_graph_node (gf ,i )-> op )|| ggml_graph_node (gf ,i )== out ) { 1640continue ; 1641 } 1642mem += tensor_op_size (ggml_graph_node (gf ,i )); 1643 } 1644 1645// run 1646int64_t total_time_us = 0 ; 1647int64_t total_mem = 0 ; 1648int total_runs = 0 ; 1649do { 1650int64_t start_time = ggml_time_us (); 1651ggml_status status = ggml_backend_graph_compute (backend ,gf ); 1652if (status != GGML_STATUS_SUCCESS ) { 1653fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1654return false; 1655 } 1656int64_t end_time = ggml_time_us (); 1657 1658total_time_us += end_time - start_time ; 1659total_mem += mem ; 1660total_runs += n_runs ; 1661 1662// re-draw any data-dependent inputs (expert ids) outside the timed region 1663reinit_perf_iter (ctx .get ()); 1664 }while (total_time_us < 1000 * 1000 );// run for at least 1 second 1665 1666// Create test result 1667double avg_time_us = (double )total_time_us /total_runs ; 1668double calculated_flops = (op_flops (out )> 0 ) ? (op_flops (out )* total_runs ) / (total_time_us /1e6 ) :0.0 ; 1669double calculated_bandwidth = 1670 (op_flops (out )== 0 ) ?total_mem / (total_time_us /1e6 ) /1024.0 /1024.0 /1024.0 :0.0 ; 1671size_t calculated_memory_kb = op_size (out ) /1024 ; 1672 1673test_result result (ggml_backend_name (backend ),current_op_name ,vars (),"perf" , true, true,"" ,avg_time_us , 1674calculated_flops ,calculated_bandwidth ,calculated_memory_kb ,total_runs ); 1675 1676if (output_printer ) { 1677output_printer -> print_test_result (result ); 1678 } 1679 1680return true; 1681 } 1682 1683bool eval_support (ggml_backend_t backend ,const char * op_names_filter ,printer * output_printer ) { 1684mode = MODE_SUPPORT ; 1685 1686static const size_t graph_nodes = 8192 ; 1687 1688ggml_init_params params = { 1689/* .mem_size = */ ggml_tensor_overhead ()* 128 + ggml_graph_overhead_custom (graph_nodes , false), 1690/* .mem_base = */ NULL , 1691/* .no_alloc = */ true, 1692 }; 1693ggml_context_ptr ctx (ggml_init (params ));// smart ptr 1694GGML_ASSERT (ctx ); 1695 1696gf = ggml_new_graph_custom (ctx .get (),graph_nodes , false); 1697 1698ggml_tensor * out = build_graph (ctx .get ()); 1699current_op_name = op_desc (out ); 1700 1701if (!matches_filter (out ,op_names_filter )) { 1702return true; 1703 } 1704 1705bool supported = ggml_backend_supports_op (backend ,out ); 1706 1707 std::string device_desc = ggml_backend_dev_description (ggml_backend_get_device (backend )); 1708 std::string backend_reg_name = ggml_backend_reg_name (ggml_backend_dev_backend_reg (ggml_backend_get_device (backend ))); 1709 1710test_result result (ggml_backend_name (backend ),current_op_name ,vars (),"support" ,supported ,supported , 1711supported ?"yes" :"no" ,0.0 ,0.0 ,0.0 ,0 ,0 ,device_desc ,backend_reg_name ); 1712 1713output_printer -> print_test_result (result ); 1714 1715return true; 1716 } 1717 1718bool eval_grad (ggml_backend_t backend ,const char * op_names_filter ,printer * output_printer ) { 1719mode = MODE_GRAD ; 1720const std::vector < float > expect = grad_expect (); 1721 1722ggml_init_params params = { 1723/* .mem_size = */ ggml_tensor_overhead ()* 128 + 2 * ggml_graph_overhead_custom (GGML_DEFAULT_GRAPH_SIZE , true), 1724/* .mem_base = */ NULL , 1725/* .no_alloc = */ true, 1726 }; 1727ggml_context_ptr ctx (ggml_init (params ));// smart ptr 1728GGML_ASSERT (ctx ); 1729 1730gf = ggml_new_graph_custom (ctx .get (),GGML_DEFAULT_GRAPH_SIZE , true); 1731gb = ggml_new_graph_custom (ctx .get (),GGML_DEFAULT_GRAPH_SIZE , true); 1732 1733ggml_tensor * out = build_graph (ctx .get ()); 1734 1735if (!matches_filter (out ,op_names_filter )|| out -> op == GGML_OP_OPT_STEP_ADAMW ) { 1736return true; 1737 } 1738 1739if (out -> type != GGML_TYPE_F32 ) { 1740output_printer -> print_operation (test_operation_info (op_desc (out ),vars (),ggml_backend_name (backend ), 1741 test_status_t::NOT_SUPPORTED , 1742out -> name + std::string ("->type != FP32" ))); 1743return true; 1744 } 1745 1746// Print operation info first 1747output_printer -> print_operation (test_operation_info (op_desc (out ),vars (),ggml_backend_name (backend ))); 1748 1749// check if the backend supports the ops 1750bool supported = true; 1751bool any_params = false; 1752 std::string failure_reason ; 1753 1754for (ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != NULL ;t = ggml_get_next_tensor (ctx .get (),t )) { 1755if (!ggml_backend_supports_op (backend ,t )) { 1756supported = false; 1757failure_reason = ggml_backend_name (backend ); 1758break ; 1759 } 1760if ((t -> flags & GGML_TENSOR_FLAG_PARAM )) { 1761any_params = true; 1762if (t -> type != GGML_TYPE_F32 ) { 1763supported = false; 1764failure_reason = std::string (t -> name )+ "->type != FP32" ; 1765break ; 1766 } 1767 } 1768 } 1769if (!any_params ) { 1770supported = false; 1771failure_reason = op_desc (out ); 1772 } 1773 1774if (!supported ) { 1775output_printer -> print_operation (test_operation_info (op_desc (out ),vars (),ggml_backend_name (backend ), 1776 test_status_t::NOT_SUPPORTED ,failure_reason )); 1777return true; 1778 } 1779 1780int64_t ngrads = 0 ; 1781for (ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != NULL ;t = ggml_get_next_tensor (ctx .get (),t )) { 1782if (t -> flags & GGML_TENSOR_FLAG_PARAM ) { 1783ngrads += ggml_nelements (t ); 1784 } 1785 } 1786if (ngrads > grad_nmax ()) { 1787test_operation_info info (op_desc (out ),vars (),ggml_backend_name (backend )); 1788info .set_large_tensor_skip (); 1789output_printer -> print_operation (info ); 1790return true; 1791 } 1792 1793 1794if (!ggml_is_scalar (out )) { 1795out = ggml_sum (ctx .get (),out ); 1796ggml_set_name (out ,"sum_of_out" ); 1797 } 1798ggml_set_loss (out ); 1799 1800ggml_build_forward_expand (gf ,out ); 1801ggml_graph_cpy (gf ,gb ); 1802ggml_build_backward_expand (ctx .get (),gb ,nullptr ); 1803if (expect .size ()!= 1 || expect [0 ]!= 0.0f ) { 1804GGML_ASSERT (ggml_graph_n_nodes (gb )> ggml_graph_n_nodes (gf )); 1805for (ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != NULL ;t = ggml_get_next_tensor (ctx .get (),t )) { 1806GGML_ASSERT (!(t -> flags & GGML_TENSOR_FLAG_PARAM )|| ggml_graph_get_grad (gb ,t )-> op != GGML_OP_NONE ); 1807 } 1808 } 1809 1810for (ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != NULL ;t = ggml_get_next_tensor (ctx .get (),t )) { 1811if (!ggml_backend_supports_op (backend ,t )) { 1812output_printer -> print_operation (test_operation_info (op_desc (out ),vars (),ggml_backend_name (backend ), 1813 test_status_t::NOT_SUPPORTED , 1814ggml_backend_name (backend ))); 1815supported = false; 1816break ; 1817 } 1818if ((t -> flags & GGML_TENSOR_FLAG_PARAM )&& t -> type != GGML_TYPE_F32 ) { 1819output_printer -> print_operation (test_operation_info (op_desc (out ),vars (),ggml_backend_name (backend ), 1820 test_status_t::NOT_SUPPORTED , 1821 std::string (t -> name )+ "->type != FP32" )); 1822supported = false; 1823break ; 1824 } 1825 } 1826if (!supported ) { 1827return true; 1828 } 1829 1830// allocate 1831ggml_backend_buffer_ptr buf (ggml_backend_alloc_ctx_tensors (ctx .get (),backend ));// smart ptr 1832if (buf == NULL ) { 1833test_operation_info info (op_desc (out ),vars (),ggml_backend_name (backend )); 1834info .set_error ("allocation" ,"" ); 1835output_printer -> print_operation (info ); 1836return false; 1837 } 1838 1839initialize_tensors (ctx .get ());// Randomizes all tensors (including gradients). 1840ggml_graph_reset (gb );// Sets gradients to 1 if loss, 0 otherwise. 1841 1842ggml_status status = ggml_backend_graph_compute (backend ,gf ); 1843if (status != GGML_STATUS_SUCCESS ) { 1844fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1845return false; 1846 } 1847status = ggml_backend_graph_compute (backend ,gb ); 1848if (status != GGML_STATUS_SUCCESS ) { 1849fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1850return false; 1851 } 1852 1853bool ok = true; 1854for (struct ggml_tensor * t = ggml_get_first_tensor (ctx .get ());t != nullptr ;t = ggml_get_next_tensor (ctx .get (),t )) { 1855if (!(t -> flags & GGML_TENSOR_FLAG_PARAM )) { 1856continue ; 1857 } 1858 1859const char * bn = ggml_backend_name (backend ); 1860const int64_t ne = ggml_nelements (t ); 1861 1862 std::vector < float > ga ; 1863struct ggml_tensor * grad = ggml_graph_get_grad (gb ,t ); 1864if (grad ) { 1865ga = tensor_to_float (grad ); 1866 }else { 1867ga .resize (ne );// default value is 0.0f 1868 } 1869 1870for (int64_t i = 0 ;i < ne ;++ i ) {// gradient algebraic 1871// check for nans 1872if (!std::isfinite (ga [i ])) { 1873test_operation_info info (op_desc (out ),vars (),ggml_backend_name (backend )); 1874info .set_gradient_info (i ,bn ,ga [i ]); 1875output_printer -> print_operation (info ); 1876ok = false; 1877break ; 1878 } 1879 } 1880if (!ok ) { 1881break ; 1882 } 1883 1884 std::vector < float > gn (ne );// gradient numeric 1885GGML_ASSERT (ga .size ()== gn .size ()); 1886 1887 std::vector < float > x0 = tensor_to_float (t );// original t data 1888GGML_ASSERT (ggml_is_scalar (out )); 1889GGML_ASSERT (out -> type == GGML_TYPE_F32 ); 1890 1891const float eps = grad_eps (); 1892for (int64_t i = 0 ;i < ne ;++ i ) { 1893const float xiu = x0 [i ]+ 1.0f * eps ;// x, index i, up 1894const float xiuh = x0 [i ]+ 0.5f * eps ;// x, index i, up half 1895const float xidh = x0 [i ]- 0.5f * eps ;// x, index i, down half 1896const float xid = x0 [i ]- 1.0f * eps ;// x, index i, down 1897 1898float fu ,fuh ,fdh ,fd ;// output values for xiu, xiuh, xid, xidh 1899 1900ggml_backend_tensor_set (t ,& xiu ,i * sizeof (float ),sizeof (float )); 1901status = ggml_backend_graph_compute (backend ,gf ); 1902if (status != GGML_STATUS_SUCCESS ) { 1903fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1904return false; 1905 } 1906ggml_backend_tensor_get (out ,& fu ,0 ,ggml_nbytes (out )); 1907 1908ggml_backend_tensor_set (t ,& xid ,i * sizeof (float ),sizeof (float )); 1909status = ggml_backend_graph_compute (backend ,gf ); 1910if (status != GGML_STATUS_SUCCESS ) { 1911fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1912return false; 1913 } 1914ggml_backend_tensor_get (out ,& fd ,0 ,ggml_nbytes (out )); 1915 1916if (grad_precise ()) { 1917ggml_backend_tensor_set (t ,& xiuh ,i * sizeof (float ),sizeof (float )); 1918status = ggml_backend_graph_compute (backend ,gf ); 1919if (status != GGML_STATUS_SUCCESS ) { 1920fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1921return false; 1922 } 1923ggml_backend_tensor_get (out ,& fuh ,0 ,ggml_nbytes (out )); 1924 1925ggml_backend_tensor_set (t ,& xidh ,i * sizeof (float ),sizeof (float )); 1926status = ggml_backend_graph_compute (backend ,gf ); 1927if (status != GGML_STATUS_SUCCESS ) { 1928fprintf (stderr ,"%s: ggml_backend_graph_compute failed. status=%s \n" ,__func__ ,ggml_status_to_string (status )); 1929return false; 1930 } 1931ggml_backend_tensor_get (out ,& fdh ,0 ,ggml_nbytes (out )); 1932 1933gn [i ]= (8.0 * (double )fuh + (double )fd - (8.0 * (double )fdh + (double )fu )) / (6.0 * (double )eps ); 1934 }else { 1935gn [i ]= (fu - fd ) / (2.0f * eps ); 1936 } 1937 1938ggml_backend_tensor_set (t ,x0 .data (),0 ,ggml_nbytes (t )); 1939 } 1940 1941const double err = mean_abs_asymm (gn .data (),ga .data (),gn .size (),expect ); 1942if (err > max_maa_err ()) { 1943test_operation_info info (op_desc (out ),vars (),ggml_backend_name (backend )); 1944info .set_maa_error (err ,max_maa_err ()); 1945output_printer -> print_operation (info ); 1946ok = false; 1947break ; 1948 } 1949if (!ok ) { 1950break ; 1951 } 1952 } 1953 1954// Create final test result 1955test_operation_info final_info (op_desc (out ),vars (),ggml_backend_name (backend )); 1956if (!ok ) { 1957final_info .set_compare_failure (); 1958 } 1959final_info .status = ok ? test_status_t::OK : test_status_t::FAIL ; 1960output_printer -> print_operation (final_info ); 1961 1962if (ok ) { 1963return true; 1964 } 1965 1966return false; 1967 } 1968}; 1969 1970 1971// #################################### 1972// ## Section 2: GGML Op Definitions ## 1973// #################################### 1974 1975 1976// The following is an example showing the bare minimum for creating a test for a GGML op. 1977 1978// GGML_OP_EXAMPLE 1979struct test_example :public test_case { 1980// Always define these 2 or variants thereof: 1981const ggml_type type ;// The type of the input tensors. 1982const std::array < int64_t ,4 > ne ;// The shape of the input tensors. 1983// For some ops it's necessary to define multiple types or shapes for the inputs. 1984// Or they may need additional parameters. 1985 1986// Put all parameters needed to fully define the test into one of the VARS_TO_STR macros. 1987// In most cases these are just the properties of the struct that you defined above. 1988// This is needed for info prints. 1989 std::string vars ()override { 1990return VARS_TO_STR2 (type ,ne ); 1991 } 1992 1993// Define a constructor for the struct. 1994// In most cases it will be sufficient to have the same arguments as the struct has properties 1995// and just use initializer lists. 1996test_example (ggml_type type = GGML_TYPE_F32 , 1997 std::array < int64_t ,4 > ne = { 10 , 5 , 4 , 3 }) 1998: type ( type ), ne ( ne ) {} 1999 2000// Define how a simple GGML compute graph can be constructed for the new GGML op. 2001ggml_tensor * build_graph (ggml_context * ctx ) override { 2002// Step 1: create input tensors that don't depend on any other tensors: 2003ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2004ggml_set_name ( a , "a" ); // Setting names is optional but it's useful for debugging. 2005 2006ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2007ggml_set_name ( b , "b" ); 2008 2009// Step 2: use the op that you want to test in the GGML compute graph. 2010ggml_tensor * out = ggml_add ( ctx , a , b ); // For this example we're just doing a simple addition. 2011ggml_set_name ( out , "out" ); 2012 2013// Step 3: return the output tensor. 2014return out ; 2015} 2016// In order to also check the gradients for your op, add calls like ggml_set_param(a) 2017// immediately after you create the tensors. 2018// This is optional and only makes sense if a backward pass has actually been implemented for the new op. 2019}; 2020 2021 2022// GGML_OP_UNARY 2023struct test_unary : public test_case { 2024const ggml_unary_op op ; 2025const ggml_type type ; 2026const std::array < int64_t, 4 > ne_a ; 2027int v ; // view (1 : non-contiguous a) 2028 2029std::string vars () override { 2030return VARS_TO_STR3 ( type , ne_a , v ); 2031} 2032 2033test_unary (ggml_unary_op op , 2034ggml_type type = GGML_TYPE_F32 , 2035std::array < int64_t, 4 > ne_a = { 128 , 2 , 2 , 2 }, 2036int v = 0 ) 2037: op ( op ), type ( type ), ne_a ( ne_a ), v ( v ) {} 2038 2039ggml_tensor * build_graph (ggml_context * ctx ) override { 2040const bool grad_supported = op == GGML_UNARY_OP_ABS || op == GGML_UNARY_OP_SGN || op == GGML_UNARY_OP_NEG || 2041op == GGML_UNARY_OP_STEP || op == GGML_UNARY_OP_RELU || op == GGML_UNARY_OP_SILU || 2042op == GGML_UNARY_OP_EXPM1 || op == GGML_UNARY_OP_SOFTPLUS ; 2043 2044ggml_tensor * a ; 2045if ( v & 1 ) { 2046auto ne = ne_a ; 2047ne [ 0 ] *= 3 ; 2048ne [ 1 ] *= 2 ; 2049ne [ 2 ] *= 5 ; 2050ne [ 3 ] *= 4 ; 2051a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2052if ( grad_supported ) { 2053ggml_set_param ( a ); 2054} 2055ggml_set_name ( a , "a" ); 2056 2057a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 2058ggml_set_name ( a , "view_of_a" ); 2059} else { 2060a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2061if ( grad_supported ) { 2062ggml_set_param ( a ); 2063} 2064ggml_set_name ( a , "a" ); 2065} 2066 2067ggml_tensor * out = ggml_unary ( ctx , a , op ); 2068ggml_set_name ( out , "out" ); 2069 2070return out ; 2071} 2072 2073void initialize_tensors (ggml_context * ctx ) override { 2074float min = -150.f ; 2075float max = 150.f ; 2076 2077// Keep FP16 exp/expm1 inputs in-range so all backends stay finite instead of 2078// disagreeing on whether overflow saturates to max-F16 or produces +inf. 2079if ( type == GGML_TYPE_F16 && ( op == GGML_UNARY_OP_EXP || op == GGML_UNARY_OP_EXPM1 )) { 2080min = -10.f ; 2081max = 10.f ; 2082} 2083 2084for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2085// test extended range of values to check for NaNs in GELU 2086init_tensor_uniform ( t , min , max ); 2087} 2088} 2089 2090float grad_eps () override { 2091return 15.0f ; 2092} 2093 2094std::vector < float > grad_expect () override { 2095if ( op == GGML_UNARY_OP_ABS ) { 2096return { -1.0f , 1.0f }; 2097} 2098if ( op == GGML_UNARY_OP_SGN || op == GGML_UNARY_OP_STEP ) { 2099return { 0.0f }; 2100} 2101if ( op == GGML_UNARY_OP_RELU ) { 2102return { 0.0f , 1.0f }; 2103} 2104return {}; 2105} 2106 2107}; 2108 2109// GGML_OP_GLU 2110struct test_glu : public test_case { 2111const ggml_glu_op op ; 2112const ggml_type type ; 2113const std::array < int64_t, 4 > ne_a ; 2114int v ; // view (1 : non-contiguous a) 2115bool swapped ; 2116 2117std::string vars () override { 2118return VARS_TO_STR4 ( type , ne_a , v , swapped ); 2119} 2120 2121test_glu (ggml_glu_op op , 2122ggml_type type = GGML_TYPE_F32 , 2123std::array < int64_t, 4 > ne_a = { 128 , 2 , 2 , 2 }, 2124int v = 0 , 2125bool swapped = false) 2126: op ( op ), type ( type ), ne_a ( ne_a ), v ( v ), swapped ( swapped ) {} 2127 2128ggml_tensor * build_graph (ggml_context * ctx ) override { 2129ggml_tensor * a ; 2130if ( v & 1 ) { 2131auto ne = ne_a ; ne [ 0 ] *= 3 ; 2132a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2133ggml_set_name ( a , "a" ); 2134 2135a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 2136ggml_set_name ( a , "view_of_a" ); 2137} else { 2138a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2139ggml_set_name ( a , "a" ); 2140} 2141 2142ggml_tensor * out = ggml_glu ( ctx , a , op , swapped ); 2143ggml_set_name ( out , "out" ); 2144 2145return out ; 2146} 2147 2148void initialize_tensors (ggml_context * ctx ) override { 2149for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2150// test extended range of values to check for NaNs in GELU 2151init_tensor_uniform ( t , -150.f , 150.f ); 2152} 2153} 2154}; 2155 2156struct test_glu_split : public test_case { 2157const ggml_glu_op op ; 2158const ggml_type type ; 2159const std::array < int64_t, 4 > ne_a ; 2160int v ; // view (1 : non-contiguous a) 2161 2162std::string vars () override { 2163return VARS_TO_STR3 ( type , ne_a , v ) + ",split" ; 2164} 2165 2166test_glu_split (ggml_glu_op op , 2167ggml_type type = GGML_TYPE_F32 , 2168std::array < int64_t, 4 > ne_a = { 128 , 2 , 2 , 2 }, 2169int v = 0 ) 2170: op ( op ), type ( type ), ne_a ( ne_a ), v ( v ) {} 2171 2172ggml_tensor * build_graph (ggml_context * ctx ) override { 2173ggml_tensor * a ; 2174ggml_tensor * b ; 2175if ( v & 1 ) { 2176auto ne = ne_a ; ne [ 0 ] *= 3 ; 2177a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2178ggml_set_param ( a ); 2179ggml_set_name ( a , "a" ); 2180 2181a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 2182ggml_set_name ( a , "view_of_a" ); 2183 2184b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2185ggml_set_param ( b ); 2186ggml_set_name ( b , "b" ); 2187 2188b = ggml_view_4d ( ctx , b , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 2189ggml_set_name ( a , "view_of_b" ); 2190} else { 2191a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2192ggml_set_param ( a ); 2193ggml_set_name ( a , "a" ); 2194 2195b = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2196ggml_set_param ( b ); 2197ggml_set_name ( b , "b" ); 2198} 2199 2200ggml_tensor * out = ggml_glu_split ( ctx , a , b , op ); 2201ggml_set_name ( out , "out" ); 2202 2203return out ; 2204} 2205 2206void initialize_tensors (ggml_context * ctx ) override { 2207for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2208// test extended range of values to check for NaNs in GELU 2209init_tensor_uniform ( t , -150.f , 150.f ); 2210} 2211} 2212}; 2213 2214struct test_swiglu_oai : public test_case { 2215const ggml_type type ; 2216const std::array < int64_t, 4 > ne_a ; 2217int v ; // view (1 : non-contiguous a) 2218float alpha ; 2219float limit ; 2220 2221std::string vars () override { 2222return VARS_TO_STR5 ( type , ne_a , v , alpha , limit ); 2223} 2224 2225test_swiglu_oai (ggml_type type = GGML_TYPE_F32 , 2226std::array < int64_t, 4 > ne_a = { 128 , 2 , 2 , 2 }, 2227int v = 0 , 2228float alpha = 1.702f , 2229float limit = 7.0f ) 2230: type ( type ), ne_a ( ne_a ), v ( v ), alpha ( alpha ), limit ( limit ) {} 2231 2232ggml_tensor * build_graph (ggml_context * ctx ) override { 2233ggml_tensor * a ; 2234ggml_tensor * b ; 2235if ( v & 1 ) { 2236auto ne = ne_a ; ne [ 0 ] *= 3 ; 2237a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2238ggml_set_param ( a ); 2239ggml_set_name ( a , "a" ); 2240 2241a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 2242ggml_set_name ( a , "view_of_a" ); 2243 2244b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2245ggml_set_param ( b ); 2246ggml_set_name ( b , "b" ); 2247 2248b = ggml_view_4d ( ctx , b , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 2249ggml_set_name ( a , "view_of_b" ); 2250} else { 2251a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2252ggml_set_param ( a ); 2253ggml_set_name ( a , "a" ); 2254 2255b = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2256ggml_set_param ( b ); 2257ggml_set_name ( b , "b" ); 2258} 2259 2260ggml_tensor * out = ggml_swiglu_oai ( ctx , a , b , alpha , limit ); 2261ggml_set_name ( out , "out" ); 2262 2263return out ; 2264} 2265 2266void initialize_tensors (ggml_context * ctx ) override { 2267for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2268// test extended range of values to check for NaNs in GELU 2269init_tensor_uniform ( t , -150.f , 150.f ); 2270} 2271} 2272}; 2273 2274struct test_swiglu_clamp : public test_case { 2275const ggml_type type ; 2276const std::array < int64_t, 4 > ne_a ; 2277int v ; // view (1 : non-contiguous a) 2278float limit ; 2279 2280std::string vars () override { 2281return VARS_TO_STR4 ( type , ne_a , v , limit ); 2282} 2283 2284test_swiglu_clamp (ggml_type type = GGML_TYPE_F32 , 2285std::array < int64_t, 4 > ne_a = { 128 , 2 , 2 , 2 }, 2286int v = 0 , 2287float limit = 7.0f ) 2288: type ( type ), ne_a ( ne_a ), v ( v ), limit ( limit ) {} 2289 2290ggml_tensor * build_graph (ggml_context * ctx ) override { 2291ggml_tensor * a ; 2292ggml_tensor * b ; 2293if ( v & 1 ) { 2294auto ne = ne_a ; ne [ 0 ] *= 3 ; 2295a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2296ggml_set_param ( a ); 2297ggml_set_name ( a , "a" ); 2298 2299a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 2300ggml_set_name ( a , "view_of_a" ); 2301 2302b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2303ggml_set_param ( b ); 2304ggml_set_name ( b , "b" ); 2305 2306b = ggml_view_4d ( ctx , b , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 2307ggml_set_name ( b , "view_of_b" ); 2308} else { 2309a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2310ggml_set_param ( a ); 2311ggml_set_name ( a , "a" ); 2312 2313b = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 2314ggml_set_param ( b ); 2315ggml_set_name ( b , "b" ); 2316} 2317 2318ggml_tensor * out = ggml_swiglu_clamp ( ctx , a , b , limit ); 2319ggml_set_name ( out , "out" ); 2320 2321return out ; 2322} 2323 2324void initialize_tensors (ggml_context * ctx ) override { 2325for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2326init_tensor_uniform ( t , -150.f , 150.f ); 2327} 2328} 2329}; 2330 2331// GGML_OP_GET_ROWS 2332struct test_get_rows : public test_case { 2333const ggml_type type ; 2334const int n ; // cols 2335const int m ; // rows 2336const int r ; // rows to get 2337const int be1 ; // batch size 2338const int be2 ; // batch size 2339const bool v ; // view src1 2340const bool vs0 ; // view src0 2341 2342std::string vars () override { 2343return VARS_TO_STR8 ( type , n , m , r , be1 , be2 , v , vs0 ); 2344} 2345 2346test_get_rows (ggml_type type = GGML_TYPE_F32 , int n = 10 , int m = 5 , int r = 3 , int be1 = 1 , int be2 = 1 , bool v = false, bool vs0 = false) 2347: type ( type ), n ( n ), m ( m ), r ( r ), be1 ( be1 ), be2 ( be2 ), v ( v ), vs0 ( vs0 ) {} 2348 2349ggml_tensor * build_graph (ggml_context * ctx ) override { 2350ggml_tensor * in ; 2351if ( vs0 ) { 2352const int offset_rows = 3 ; 2353const int padded_m = m + offset_rows ; 2354ggml_tensor * in_padded = ggml_new_tensor_4d ( ctx , type , n , padded_m , be1 , be2 ); 2355ggml_set_name ( in_padded , "in_padded" ); 2356in = ggml_view_4d ( ctx , in_padded , n , m , be1 , be2 , 2357in_padded -> nb [ 1 ], in_padded -> nb [ 2 ], in_padded -> nb [ 3 ], 2358offset_rows * in_padded -> nb [ 1 ]); 2359ggml_set_name ( in , "in_view" ); 2360} else { 2361in = ggml_new_tensor_4d ( ctx , type , n , m , be1 , be2 ); 2362ggml_set_name ( in , "in" ); 2363} 2364 2365ggml_tensor * rows = ggml_new_tensor_3d ( ctx , GGML_TYPE_I32 , v ? r + 1 : r , be1 , be2 ); 2366ggml_set_name ( rows , "rows" ); 2367if ( v ) { 2368rows = ggml_view_3d ( ctx , rows , r / 2 , be1 , be2 , rows -> nb [ 1 ], rows -> nb [ 2 ], rows -> nb [ 0 ]); 2369ggml_set_name ( rows , "view_of_rows" ); 2370} 2371 2372const bool grad_supported = ! vs0 && ggml_is_matrix ( in ) && ggml_is_vector ( rows ); 2373if ( grad_supported ) { 2374ggml_set_param ( in ); 2375// rows is a constant input -> no gradients 2376} 2377 2378ggml_tensor * out = ggml_get_rows ( ctx , in , rows ); 2379ggml_set_name ( out , "out" ); 2380 2381return out ; 2382} 2383 2384void initialize_tensors (ggml_context * ctx ) override { 2385for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2386if ( ggml_is_view_op ( t -> op )) { 2387continue ; 2388} 2389if ( t -> type == GGML_TYPE_I32 ) { 2390// rows 2391std::vector < int > data ( ggml_nelements ( t )); 2392for (size_t i = 0 ; i < data . size (); i ++ ) { 2393data [ i ] = rand () % m ; 2394} 2395ggml_backend_tensor_set ( t , data . data (), 0 , data . size () * sizeof (int)); 2396} else { 2397init_tensor_uniform ( t ); 2398} 2399} 2400} 2401}; 2402 2403// GGML_OP_GET_ROWS_BACK 2404struct test_get_rows_back : public test_case { 2405const ggml_type type ; 2406const int n ; // cols 2407const int m ; // rows 2408const int r ; // rows to get 2409const int b ; // batch size 2410const bool v ; // view (non-contiguous src1) 2411 2412std::string vars () override { 2413return VARS_TO_STR6 ( type , n , m , r , b , v ); 2414} 2415 2416test_get_rows_back (ggml_type type = GGML_TYPE_F32 , int n = 10 , int m = 5 , int r = 3 , int b = 1 , bool v = false) 2417: type ( type ), n ( n ), m ( m ), r ( r ), b ( b ), v ( v ) {} 2418 2419ggml_tensor * build_graph (ggml_context * ctx ) override { 2420ggml_tensor * in_forward = ggml_new_tensor_3d ( ctx , type , n , m , b ); 2421ggml_set_name ( in_forward , "in_forward" ); 2422 2423ggml_tensor * rows = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , r , b ); 2424ggml_set_name ( rows , "rows" ); 2425if ( v ) { 2426rows = ggml_view_2d ( ctx , rows , r / 2 , b , rows -> nb [ 1 ], 0 ); 2427ggml_set_name ( rows , "view_of_rows" ); 2428} 2429 2430ggml_tensor * grad = ggml_new_tensor_3d ( ctx , type , n , r , b ); 2431ggml_set_name ( grad , "grad" ); 2432 2433ggml_tensor * out = ggml_get_rows_back ( ctx , grad , rows , in_forward ); 2434ggml_set_name ( out , "out" ); 2435 2436return out ; 2437} 2438 2439void initialize_tensors (ggml_context * ctx ) override { 2440for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2441if ( t -> type == GGML_TYPE_I32 ) { 2442if ( ggml_is_view_op ( t -> op )) { continue ; } 2443// rows 2444std::vector < int > data (r * b ); 2445for (int i = 0 ; i < r * b ; i ++ ) { 2446data [ i ] = rand () % m ; 2447} 2448ggml_backend_tensor_set ( t , data . data (), 0 , r * b * sizeof (int)); 2449} else { 2450init_tensor_uniform ( t ); 2451} 2452} 2453} 2454}; 2455 2456static void init_set_rows_row_ids (ggml_tensor * t , int num_rows ) { 2457std::random_device rd ; 2458std::default_random_engine rng ( rd ()); 2459for (int i2 = 0 ; i2 < t -> ne [ 2 ]; i2 ++ ) { 2460for (int i1 = 0 ; i1 < t -> ne [ 1 ]; i1 ++ ) { 2461// generate a shuffled subset of row indices 2462std::vector < int64_t > data (num_rows); 2463for (int i = 0 ; i < num_rows ; i ++ ) { 2464data [ i ] = i ; 2465} 2466std:: shuffle ( data . begin (), data . end (), rng ); 2467data . resize ( t -> ne [ 0 ]); 2468 2469const size_t offs = i1 * t -> nb [ 1 ] + i2 * t -> nb [ 2 ]; 2470if ( t -> type == GGML_TYPE_I32 ) { 2471// TODO: Make a template or something 2472std::vector < int32_t > data_i32 ( t -> ne [ 0 ]); 2473for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 2474data_i32 [ i ] = static_cast < int32_t > ( data [ i ]); 2475} 2476ggml_backend_tensor_set ( t , data_i32 . data (), offs , t -> ne [ 0 ] * sizeof (int32_t)); 2477} else { 2478ggml_backend_tensor_set ( t , data . data (), offs , t -> ne [ 0 ] * sizeof (int64_t)); 2479} 2480} 2481} 2482} 2483 2484// GGML_OP_SET_ROWS 2485struct test_set_rows : public test_case { 2486const ggml_type type_src ; 2487const ggml_type type_dst ; 2488const ggml_type type_idx ; 2489const std::array < int64_t, 4 > ne ; 2490const std::array < int, 2 > nr23 ; // broadcast only dims 2 and 3 2491const int r ; // rows to set 2492const bool v ; // view (non-contiguous src1) 2493 2494std::string vars () override { 2495return VARS_TO_STR7 ( type_src , type_dst , type_idx , ne , nr23 , r , v ); 2496} 2497 2498test_set_rows (ggml_type type_src , 2499ggml_type type_dst , 2500ggml_type type_idx , 2501std::array < int64_t, 4 > ne , 2502std::array < int, 2 > nr23 , 2503int r , bool v = false) 2504: type_src ( type_src ), type_dst ( type_dst ), type_idx ( type_idx ), ne ( ne ), nr23 ( nr23 ), r ( r ), v ( v ) {} 2505 2506ggml_tensor * build_graph (ggml_context * ctx ) override { 2507ggml_tensor * dst = ggml_new_tensor_4d ( ctx , type_dst , ne [ 0 ], ne [ 1 ], ne [ 2 ] * nr23 [ 0 ], ne [ 3 ] * nr23 [ 1 ]); 2508ggml_set_name ( dst , "dst" ); 2509 2510ggml_tensor * src = ggml_new_tensor_4d ( ctx , type_src , ne [ 0 ], r , ne [ 2 ] * nr23 [ 0 ], ne [ 3 ] * nr23 [ 1 ]); 2511ggml_set_name ( src , "src" ); 2512 2513ggml_tensor * row_idxs = ggml_new_tensor_3d ( ctx , type_idx , r , ne [ 2 ], ne [ 3 ]); 2514ggml_set_name ( row_idxs , "row_idxs" ); 2515 2516if ( v ) { 2517src = ggml_view_4d ( ctx , src , ne [ 0 ], r / 2 , ne [ 2 ] * nr23 [ 0 ], ne [ 3 ] * nr23 [ 1 ], src -> nb [ 1 ], src -> nb [ 2 ], src -> nb [ 3 ], 0 ); 2518row_idxs = ggml_view_3d ( ctx , row_idxs , r / 2 , ne [ 2 ], ne [ 3 ], row_idxs -> nb [ 1 ], row_idxs -> nb [ 2 ], 0 ); 2519ggml_set_name ( row_idxs , "view_of_rows" ); 2520} 2521 2522ggml_tensor * out = ggml_set_rows ( ctx , dst , src , row_idxs ); 2523ggml_set_name ( out , "out" ); 2524 2525return out ; 2526} 2527 2528void initialize_tensors (ggml_context * ctx ) override { 2529for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2530if ( ggml_is_view_op ( t -> op )) { 2531continue ; 2532} 2533if ( t -> type == GGML_TYPE_I64 || t -> type == GGML_TYPE_I32 ) { 2534init_set_rows_row_ids ( t , ne [ 1 ]); 2535} else { 2536init_tensor_uniform ( t ); 2537} 2538} 2539} 2540 2541double max_nmse_err () override { 2542if ( type_dst == GGML_TYPE_Q2_0 || type_dst == GGML_TYPE_Q4_0 || type_dst == GGML_TYPE_Q4_1 || 2543type_dst == GGML_TYPE_IQ4_NL || 2544type_dst == GGML_TYPE_Q5_0 || type_dst == GGML_TYPE_Q5_1 || type_dst == GGML_TYPE_Q8_0 ) { 2545// estimate what the max nmse error would be if one quantized value is 2546// off by one. The test values are distributed in [-1,1], so it'll be 2547// roughly (2.0 / 2^bits)^2, divided by the mean square value of the reference, 2548// which is roughly 0.25 times the number of elements. 2549double err_estimate = 1.0f / 8.0f ; 2550if ( type_src == GGML_TYPE_F16 && type_dst == GGML_TYPE_Q2_0 ) { 2551err_estimate *= 4.0f ; 2552} 2553if ( type_dst == GGML_TYPE_Q5_0 || type_dst == GGML_TYPE_Q5_1 ) { 2554err_estimate /= 2.0f ; 2555} 2556if ( type_dst == GGML_TYPE_Q8_0 ) { 2557err_estimate /= 8.0f ; 2558} 2559err_estimate *= err_estimate ; 2560if ( type_src == GGML_TYPE_F16 ) { 2561err_estimate *= 16.0f ; 2562} 2563err_estimate /= 0.25f * float( ne [ 0 ] * r * ne [ 2 ] * nr23 [ 0 ] * ne [ 3 ] * nr23 [ 1 ]); 2564return err_estimate ; 2565} 2566return 1e-7 ; 2567} 2568 2569// See dicussion here: https://github.com/ggml-org/llama.cpp/pull/23760#issuecomment-4566312209 2570double max_nmse_err (ggml_backend_t backend ) override { 2571ggml_backend_reg_t reg = ggml_backend_dev_backend_reg ( ggml_backend_get_device ( backend )); 2572if ( type_dst == GGML_TYPE_Q8_0 ) { 2573if ( strcmp ( ggml_backend_reg_name ( reg ), "WebGPU" ) == 0 ) { 2574return std:: max (test_case:: max_nmse_err ( backend ), 2e-7 ); 2575} 2576if ( strcmp ( ggml_backend_reg_name ( reg ), "HTP" ) == 0 ) { 2577return std:: max (test_case:: max_nmse_err ( backend ), 5e-6 ); 2578} 2579} 2580return test_case:: max_nmse_err ( backend ); 2581} 2582}; 2583 2584// GGML_OP_ROPE + GGML_OP_VIEW + GGML_OP_SET_ROWS 2585struct test_rope_set_rows : public test_case { 2586const ggml_type type ; 2587const ggml_type type_idx ; 2588const std::array < int64_t, 4 > ne_a ; 2589int mode ; 2590const int n_ctx { 512 }; 2591const int n_dims { 128 }; 2592 2593std::string vars () override { 2594return VARS_TO_STR4 ( type , type_idx , ne_a , mode ); 2595} 2596 2597std::string op_desc (ggml_tensor * t ) override { 2598GGML_UNUSED ( t ); 2599return "ROPE_SET_ROWS" ; 2600} 2601 2602bool run_whole_graph () override { return true; } 2603 2604test_rope_set_rows (ggml_type type , 2605ggml_type type_idx , 2606std::array < int64_t, 4 > ne_a , 2607int mode ) 2608: type ( type ), type_idx ( type_idx ), ne_a ( ne_a ), mode ( mode ) {} 2609 2610ggml_tensor * build_graph (ggml_context * ctx ) override { 2611ggml_tensor * a = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], 1 ); 2612ggml_set_name ( a , "a" ); 2613 2614const bool is_mrope = mode & GGML_ROPE_TYPE_MROPE ; 2615const bool is_vision = mode == GGML_ROPE_TYPE_VISION ; 2616 2617ggml_tensor * pos ; 2618if ( is_mrope || is_vision ) { 2619pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , ne_a [ 2 ] * 4 ); 2620} else { 2621pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , ne_a [ 2 ]); 2622} 2623ggml_set_name ( pos , "pos" ); 2624 2625float fs = 1.4245f ; 2626float ef = 0.7465f ; 2627float af = 1.4245f ; 2628ggml_tensor * freq = nullptr ; 2629 2630ggml_tensor * rope = nullptr ; 2631if ( is_mrope ) { 2632if ( is_vision ) { 2633GGML_ASSERT ( n_dims / 4 > 0 ); 2634int rope_sections [ 4 ] = { n_dims / 4 , n_dims / 4 , 0 , 0 }; // Vision-RoPE only use first two dimension for image (x, y) coordinate 2635rope = ggml_rope_multi ( ctx , a , pos , freq , n_dims / 2 , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 2636} else { 2637GGML_ASSERT ( n_dims / 3 > 0 ); 2638int rope_sections [ 4 ] = { n_dims / 3 , n_dims / 3 , n_dims / 3 , 0 }; 2639rope = ggml_rope_multi ( ctx , a , pos , freq , n_dims , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 2640} 2641} else { 2642rope = ggml_rope ( ctx , a , pos , ne_a [ 0 ], mode ); 2643} 2644 2645ggml_tensor * view = ggml_view_2d ( ctx , rope , ne_a [ 0 ] * ne_a [ 1 ], ne_a [ 2 ], rope -> nb [ 2 ], 0 ); 2646 2647ggml_tensor * dst = ggml_new_tensor_4d ( ctx , type , ne_a [ 0 ] * ne_a [ 1 ], ne_a [ 2 ] * ne_a [ 3 ], 1 , 1 ); 2648ggml_set_name ( dst , "dst" ); 2649 2650ggml_tensor * row_idxs = ggml_new_tensor_3d ( ctx , type_idx , ne_a [ 2 ], 1 , 1 ); 2651ggml_set_name ( row_idxs , "row_idxs" ); 2652 2653ggml_tensor * out = ggml_set_rows ( ctx , dst , view , row_idxs ); 2654ggml_set_name ( out , "out" ); 2655 2656return out ; 2657} 2658 2659void initialize_tensors (ggml_context * ctx ) override { 2660for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2661if ( strcmp ( t -> name , "row_idxs" ) == 0 ) { 2662if ( ggml_is_view_op ( t -> op )) { 2663continue ; 2664} 2665init_set_rows_row_ids ( t , ne_a [ 2 ]); 2666} else if ( t -> type == GGML_TYPE_I32 ) { 2667// pos 2668const int num_pos_ids = ( mode & GGML_ROPE_TYPE_MROPE ) ? ne_a [ 2 ] * 4 : ne_a [ 2 ]; 2669std::vector < int > data (num_pos_ids); 2670for (int i = 0 ; i < num_pos_ids ; i ++ ) { 2671data [ i ] = rand () % n_ctx ; 2672} 2673ggml_backend_tensor_set ( t , data . data (), 0 , num_pos_ids * sizeof (int)); 2674} else { 2675if ( t -> ne [ 0 ] == n_dims / 2 ) { 2676// frequency factors in the range [0.9f, 1.1f] 2677init_tensor_uniform ( t , 0.9f , 1.1f ); 2678} else { 2679init_tensor_uniform ( t ); 2680} 2681} 2682} 2683} 2684}; 2685 2686// GGML_OP_RMS_NORM with optional GGML_OP_MUL, GGML_OP_ROPE, GGML_OP_VIEW and GGML_OP_SET_ROWS 2687struct test_rms_norm_mul_rope : public test_case { 2688const std::array < int64_t, 4 > ne ; 2689const float eps ; 2690const bool multi_add ; // test a sequence of adds feeding into rms_norm 2691const bool mul ; 2692const bool rope ; 2693const bool set_rows ; 2694const bool broadcast ; // multiply by a 1D [ne0] weight, as model norm weights are 2695const ggml_type set_rows_type ; 2696int mode ; 2697 2698std::string op_desc (ggml_tensor * t ) override { 2699GGML_UNUSED ( t ); 2700return "RMS_NORM_MUL_ROPE" ; 2701} 2702 2703bool run_whole_graph () override { return true; } 2704 2705std::string vars () override { 2706return VARS_TO_STR9 ( ne , eps , multi_add , mul , rope , set_rows , broadcast , mode , set_rows_type ); 2707} 2708 2709test_rms_norm_mul_rope (std::array < int64_t, 4 > ne , float eps = 1e-6f , bool multi_add = false, 2710bool set_rows = false, bool broadcast = false, int mode = GGML_ROPE_TYPE_NORMAL , 2711bool mul = true, bool rope = true, ggml_type set_rows_type = GGML_TYPE_F16 ) 2712: ne ( ne ), eps ( eps ), multi_add ( multi_add ), mul ( mul ), rope ( rope ), set_rows ( set_rows ), broadcast ( broadcast ), 2713set_rows_type ( set_rows_type ), mode ( mode ) {} 2714 2715ggml_tensor * build_graph (ggml_context * ctx ) override { 2716ggml_tensor * a = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 2717 2718ggml_tensor * b = nullptr ; 2719ggml_tensor * c = nullptr ; 2720ggml_tensor * w = nullptr ; 2721 2722if ( multi_add || ( mul && ! broadcast )) { 2723b = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , ne [ 0 ], ne [ 1 ], ne [ 2 ], 1 ); 2724} 2725if ( multi_add ) { 2726c = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , ne [ 0 ], ne [ 1 ], ne [ 2 ], 1 ); 2727} 2728if ( mul ) { 2729w = broadcast ? ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , ne [ 0 ]) : b ; 2730} 2731 2732if ( multi_add ) { 2733a = ggml_add ( ctx , ggml_add ( ctx , a , b ), c ); 2734} 2735 2736a = ggml_rms_norm ( ctx , a , eps ); 2737 2738if ( mul ) { 2739a = ggml_mul ( ctx , a , w ); 2740} 2741 2742if ( rope ) { 2743const bool is_mrope = mode & GGML_ROPE_TYPE_MROPE ; 2744ggml_tensor * pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , ne [ 2 ] * ( is_mrope ? 4 : 1 )); 2745 2746if ( is_mrope ) { 2747const int n_dims = ne [ 0 ]; 2748int sections [ 4 ] = { n_dims / 3 , n_dims / 3 , n_dims / 3 , 0 }; 2749a = ggml_rope_multi ( ctx , a , pos , nullptr , n_dims , sections , mode , 0 , 10000.0f , 1.0f , 0.0f , 1.0f , 32.0f , 1.0f ); 2750} else { 2751a = ggml_rope ( ctx , a , pos , ne [ 0 ], mode ); 2752} 2753} 2754 2755if ( set_rows ) { 2756ggml_tensor * view = ggml_view_2d ( ctx , a , ne [ 0 ] * ne [ 1 ], ne [ 2 ], a -> nb [ 2 ], 0 ); 2757 2758ggml_tensor * dst = ggml_new_tensor_2d ( ctx , set_rows_type , ne [ 0 ] * ne [ 1 ], ne [ 2 ] * 2 ); 2759ggml_set_name ( dst , "dst" ); 2760 2761ggml_tensor * row_idxs = ggml_new_tensor_1d ( ctx , GGML_TYPE_I64 , ne [ 2 ]); 2762ggml_set_name ( row_idxs , "row_idxs" ); 2763 2764a = ggml_set_rows ( ctx , dst , view , row_idxs ); 2765} 2766 2767ggml_set_name ( a , "out" ); 2768return a ; 2769} 2770 2771void initialize_tensors (ggml_context * ctx ) override { 2772for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2773if ( t -> type == GGML_TYPE_I64 ) { 2774init_set_rows_row_ids ( t , ne [ 2 ] * 2 ); 2775} else if ( t -> type == GGML_TYPE_I32 ) { 2776std::vector < int32_t > data ( ggml_nelements ( t )); 2777for (int32_t & value : data ) { 2778value = rand () % 512 ; 2779} 2780ggml_backend_tensor_set ( t , data . data (), 0 , ggml_nbytes ( t )); 2781} else { 2782init_tensor_uniform ( t ); 2783} 2784} 2785} 2786 2787double max_nmse_err () override { 2788return ne [ 0 ] == 8192 ? 5e-6 : test_case:: max_nmse_err (); 2789} 2790}; 2791 2792// GGML_OP_ARGMAX 2793struct test_argmax : public test_case { 2794const ggml_type type ; 2795const std::array < int64_t, 4 > ne ; 2796 2797std::string vars () override { 2798return VARS_TO_STR2 ( type , ne ); 2799} 2800 2801test_argmax (ggml_type type = GGML_TYPE_F32 , 2802std::array < int64_t, 4 > ne = { 10 , 100 , 1 , 1 }) 2803: type ( type ), ne ( ne ) {} 2804 2805ggml_tensor * build_graph (ggml_context * ctx ) override { 2806ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2807ggml_set_name ( a , "a" ); 2808 2809ggml_tensor * out = ggml_argmax ( ctx , a ); 2810ggml_set_name ( out , "out" ); 2811 2812return out ; 2813} 2814 2815void initialize_tensors (ggml_context * ctx ) override { 2816std::random_device rd ; 2817std::default_random_engine rng ( rd ()); 2818for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2819if ( t -> type == GGML_TYPE_F32 ) { 2820// initialize with unique values to avoid ties 2821for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 2822std::vector < float > data ( t -> ne [ 0 ]); 2823for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 2824data [ i ] = i ; 2825} 2826std:: shuffle ( data . begin (), data . end (), rng ); 2827ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (float)); 2828} 2829} else { 2830init_tensor_uniform ( t ); 2831} 2832} 2833} 2834 2835double max_nmse_err () override { 2836return 0.0 ; 2837} 2838}; 2839 2840// GGML_OP_COUNT_EQUAL 2841struct test_count_equal : public test_case { 2842const ggml_type type ; 2843const std::array < int64_t, 4 > ne ; 2844 2845std::string vars () override { 2846return VARS_TO_STR2 ( type , ne ); 2847} 2848 2849test_count_equal (ggml_type type = GGML_TYPE_F32 , 2850std::array < int64_t, 4 > ne = { 4 , 500 , 1 , 1 }) 2851: type ( type ), ne ( ne ) {} 2852 2853ggml_tensor * build_graph (ggml_context * ctx ) override { 2854ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2855ggml_set_name ( a , "a" ); 2856 2857ggml_tensor * a_argmax = ggml_argmax ( ctx , a ); 2858ggml_set_name ( a_argmax , "a_argmax" ); 2859 2860ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2861ggml_set_name ( b , "b" ); 2862 2863ggml_tensor * b_argmax = ggml_argmax ( ctx , b ); 2864ggml_set_name ( b_argmax , "b_argmax" ); 2865 2866ggml_tensor * out = ggml_count_equal ( ctx , a_argmax , b_argmax ); 2867ggml_set_name ( out , "out" ); 2868 2869return out ; 2870} 2871 2872double max_nmse_err () override { 2873return 0.0 ; 2874} 2875 2876void initialize_tensors (ggml_context * ctx ) override { 2877std::random_device rd ; 2878std::default_random_engine rng ( rd ()); 2879for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 2880if ( t -> type == GGML_TYPE_F32 ) { 2881// initialize with unique values to avoid ties 2882for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 2883std::vector < float > data ( t -> ne [ 0 ]); 2884for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 2885data [ i ] = i ; 2886} 2887std:: shuffle ( data . begin (), data . end (), rng ); 2888ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (float)); 2889} 2890} else { 2891init_tensor_uniform ( t ); 2892} 2893} 2894} 2895}; 2896 2897// GGML_OP_REPEAT 2898struct test_repeat : public test_case { 2899const ggml_type type ; 2900const std::array < int64_t, 4 > ne ; 2901const std::array < int, 4 > nr ; 2902 2903std::string vars () override { 2904return VARS_TO_STR3 ( type , ne , nr ); 2905} 2906 2907size_t op_size (ggml_tensor * t ) override { 2908return ggml_nbytes ( t ) * 2 ; 2909} 2910 2911test_repeat (ggml_type type = GGML_TYPE_F32 , 2912std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 2913std::array < int, 4 > nr = { 2 , 2 , 2 , 2 }) 2914: type ( type ), ne ( ne ), nr ( nr ) {} 2915 2916ggml_tensor * build_graph (ggml_context * ctx ) override { 2917ggml_tensor * target = ggml_new_tensor_4d ( ctx , type , ne [ 0 ] * nr [ 0 ], ne [ 1 ] * nr [ 1 ], ne [ 2 ] * nr [ 2 ], ne [ 3 ] * nr [ 3 ]); 2918ggml_set_name ( target , "target" ); 2919 2920ggml_tensor * src = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2921ggml_set_param ( src ); 2922ggml_set_name ( src , "src" ); 2923 2924ggml_tensor * out = ggml_repeat ( ctx , src , target ); 2925ggml_set_name ( out , "out" ); 2926 2927return out ; 2928} 2929}; 2930 2931// GGML_OP_REPEAT_BACK 2932struct test_repeat_back : public test_case { 2933const ggml_type type ; 2934const std::array < int64_t, 4 > ne ; 2935const std::array < int, 4 > nr ; 2936const bool v ; // whether src is a noncontiguous view 2937 2938std::string vars () override { 2939return VARS_TO_STR4 ( type , ne , nr , v ); 2940} 2941 2942size_t op_size (ggml_tensor * t ) override { 2943return ggml_nbytes ( t ) * 2 ; 2944} 2945 2946test_repeat_back (ggml_type type = GGML_TYPE_F32 , 2947std::array < int64_t, 4 > ne = { 8 , 6 , 4 , 2 }, 2948std::array < int, 4 > nr = { 2 , 2 , 2 , 2 }, 2949bool v = false) 2950: type ( type ), ne ( ne ), nr ( nr ), v ( v ) {} 2951 2952ggml_tensor * build_graph (ggml_context * ctx ) override { 2953ggml_tensor * src = ggml_new_tensor_4d ( ctx , type , ne [ 0 ] * nr [ 0 ], ne [ 1 ] * nr [ 1 ], ne [ 2 ] * nr [ 2 ], ne [ 3 ] * nr [ 3 ]); 2954ggml_set_name ( src , "src" ); 2955 2956if ( v ) { 2957GGML_ASSERT ( ne [ 0 ] % 2 == 0 ); 2958GGML_ASSERT ( ne [ 1 ] % 2 == 0 ); 2959GGML_ASSERT ( ne [ 2 ] % 2 == 0 ); 2960GGML_ASSERT ( ne [ 3 ] % 2 == 0 ); 2961GGML_ASSERT ( nr [ 0 ] % 2 == 0 || nr [ 0 ] == 1 ); 2962GGML_ASSERT ( nr [ 1 ] % 2 == 0 || nr [ 1 ] == 1 ); 2963GGML_ASSERT ( nr [ 2 ] % 2 == 0 || nr [ 2 ] == 1 ); 2964GGML_ASSERT ( nr [ 3 ] % 2 == 0 || nr [ 3 ] == 1 ); 2965 2966const int64_t ne00 = nr [ 0 ] == 1 ? src -> ne [ 0 ] : src -> ne [ 0 ] / 2 ; 2967const int64_t ne01 = nr [ 1 ] == 1 ? src -> ne [ 1 ] : src -> ne [ 1 ] / 2 ; 2968const int64_t ne02 = nr [ 2 ] == 1 ? src -> ne [ 2 ] : src -> ne [ 2 ] / 2 ; 2969const int64_t ne03 = nr [ 3 ] == 1 ? src -> ne [ 3 ] : src -> ne [ 3 ] / 2 ; 2970 2971src = ggml_view_4d ( ctx , src , ne00 , ne01 , ne02 , ne03 , src -> nb [ 1 ], src -> nb [ 2 ], src -> nb [ 3 ], 0 ); 2972} 2973 2974ggml_tensor * target = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 2975ggml_set_name ( target , "target" ); 2976 2977ggml_tensor * out = ggml_repeat_back ( ctx , src , target ); 2978ggml_set_name ( out , "out" ); 2979 2980return out ; 2981} 2982}; 2983 2984// GGML_OP_DUP 2985struct test_dup : public test_case { 2986const ggml_type type ; 2987const std::array < int64_t, 4 > ne ; 2988const std::array < int64_t, 4 > permute ; 2989bool _use_permute ; 2990 2991std::string vars () override { 2992std::string v = VARS_TO_STR2 ( type , ne ); 2993if ( _use_permute ) v += "," + VAR_TO_STR ( permute ); 2994return v ; 2995} 2996 2997test_dup (ggml_type type = GGML_TYPE_F32 , 2998std::array < int64_t, 4 > ne = { 10 , 10 , 20 , 1 }, 2999std::array < int64_t, 4 > permute = { 0 , 0 , 0 , 0 }) 3000: type ( type ), ne ( ne ), permute ( permute ), 3001_use_permute ( permute [ 0 ] + permute [ 1 ] + permute [ 2 ] + permute [ 3 ] > 0 ) {} 3002 3003ggml_tensor * build_graph (ggml_context * ctx ) override { 3004ggml_tensor * src = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3005ggml_set_param ( src ); 3006ggml_set_name ( src , "src" ); 3007 3008if ( _use_permute ) { 3009src = ggml_permute ( ctx , src , permute [ 0 ], permute [ 1 ], permute [ 2 ], permute [ 3 ]); 3010ggml_set_name ( src , "src_permuted" ); 3011} 3012 3013ggml_tensor * out = ggml_dup ( ctx , src ); 3014ggml_set_name ( out , "out" ); 3015 3016return out ; 3017} 3018}; 3019 3020// GGML_OP_SET 3021struct test_set : public test_case { 3022const ggml_type type_src ; 3023const ggml_type type_dst ; 3024const std::array < int64_t, 4 > ne ; 3025const int dim ; 3026const bool inplace ; 3027 3028std::string vars () override { 3029return VARS_TO_STR5 ( type_src , type_dst , ne , dim , inplace ); 3030} 3031 3032size_t op_size (ggml_tensor * t ) override { 3033return ggml_nbytes ( t ) + ggml_nbytes ( t -> src [ 0 ]); 3034} 3035 3036test_set (ggml_type type_src = GGML_TYPE_F32 , ggml_type type_dst = GGML_TYPE_F32 , 3037std::array < int64_t, 4 > ne = { 6 , 5 , 4 , 3 }, int dim = 1 , bool inplace = false) 3038: type_src ( type_src ), type_dst ( type_dst ), ne ( ne ), dim ( dim ), inplace ( inplace ) {} 3039 3040ggml_tensor * build_graph (ggml_context * ctx ) override { 3041ggml_tensor * src = ggml_new_tensor ( ctx , type_src , 4 , ne . data ()); 3042ggml_set_param ( src ); 3043ggml_set_name ( src , "src" ); 3044 3045auto ne_dst = ne ; 3046for (int i = 0 ; i < dim ; ++ i ) { 3047ne_dst [ i ] *= 2 ; 3048} 3049ggml_tensor * dst = ggml_new_tensor ( ctx , type_dst , 4 , ne_dst . data ()); 3050ggml_set_param ( dst ); 3051ggml_set_name ( dst , "dst" ); 3052 3053size_t offset = 0 ; 3054for (int i = 0 ; i < dim ; ++ i ) { 3055offset += (( ne_dst [ i ] - ne [ i ])/ 2 ) * dst -> nb [ i ]; 3056} 3057ggml_tensor * out ; 3058if ( inplace ) { 3059out = ggml_set_inplace ( ctx , dst , src , 3060// The backward pass requires setting a contiguous region: 3061src -> nb [ 1 ], src -> nb [ 2 ], src -> nb [ 3 ], offset ); 3062} else { 3063out = ggml_set ( ctx , dst , src , 3064// The backward pass requires setting a contiguous region: 3065src -> nb [ 1 ], src -> nb [ 2 ], src -> nb [ 3 ], offset ); 3066} 3067ggml_set_name ( out , "out" ); 3068 3069return out ; 3070} 3071}; 3072 3073// GGML_OP_CPY 3074struct test_cpy : public test_case { 3075const ggml_type type_src ; 3076const ggml_type type_dst ; 3077const std::array < int64_t, 4 > ne_src ; 3078const std::array < int64_t, 4 > ne_dst ; 3079const std::array < int64_t, 4 > permute_src ; 3080const std::array < int64_t, 4 > permute_dst ; 3081const std::array < int64_t, 4 > dst_alloc ; // if set, dst is a view into a larger buffer (strided) 3082bool _src_use_permute ; 3083bool _dst_use_permute ; 3084bool _src_transpose ; 3085bool _use_dst_shape ; 3086bool _use_dst_alloc ; 3087 3088std::string vars () override { 3089if ( _use_dst_alloc ) { 3090return VARS_TO_STR8 ( type_src , type_dst , ne_src , ne_dst , permute_src , permute_dst , _src_transpose , dst_alloc ); 3091} 3092if ( _use_dst_shape ) { 3093return VARS_TO_STR7 ( type_src , type_dst , ne_src , ne_dst , permute_src , permute_dst , _src_transpose ); 3094} 3095return VARS_TO_STR6 ( type_src , type_dst , ne_src , permute_src , permute_dst , _src_transpose ); 3096} 3097 3098int64_t total_elements () const { 3099return ne_src [ 0 ] * ne_src [ 1 ] * ne_src [ 2 ] * ne_src [ 3 ]; 3100} 3101 3102double max_nmse_err () override { 3103if ( type_src == type_dst ) { 3104return 0.0 ; 3105} 3106if ( type_dst == GGML_TYPE_Q4_0 || type_dst == GGML_TYPE_Q4_1 || type_dst == GGML_TYPE_IQ4_NL || 3107type_dst == GGML_TYPE_Q5_0 || type_dst == GGML_TYPE_Q5_1 || type_dst == GGML_TYPE_Q8_0 ) { 3108// estimate what the max nmse error would be if one quantized value is 3109// off by one. The test values are distributed in [-150,150], so it'll be 3110// roughly (150*2.0 / 2^bits)^2, divided by the mean square value of the reference, 3111// which is roughly 0.25*150^2 times the number of elements. 3112double err_estimate = 1.0f / 8.0f * 150.0f ; 3113if ( type_dst == GGML_TYPE_IQ4_NL ) { 3114// iq4_nl values are a bit more spread out 3115err_estimate *= 2.0f ; 3116} 3117if ( type_dst == GGML_TYPE_Q5_0 || type_dst == GGML_TYPE_Q5_1 ) { 3118err_estimate /= 2.0f ; 3119} 3120if ( type_dst == GGML_TYPE_Q8_0 ) { 3121err_estimate /= 8.0f ; 3122} 3123err_estimate *= err_estimate ; 3124err_estimate /= ( 150.0f * 150.0f * 0.25f ) * float( total_elements ()); 3125return err_estimate ; 3126} 3127return 1e-6 ; 3128} 3129 3130size_t op_size (ggml_tensor * t ) override { 3131return ggml_nbytes ( t ) + ggml_nbytes ( t -> src [ 0 ]); 3132} 3133 3134test_cpy (ggml_type type_src = GGML_TYPE_F32 , ggml_type type_dst = GGML_TYPE_F32 , 3135std::array < int64_t, 4 > ne_src = { 10 , 10 , 10 , 1 }, 3136std::array < int64_t, 4 > ne_dst = { -1 , -1 , -1 , -1 }, 3137std::array < int64_t, 4 > permute_src = { 0 , 0 , 0 , 0 }, 3138std::array < int64_t, 4 > permute_dst = { 0 , 0 , 0 , 0 }, 3139bool transpose_src = false, 3140std::array < int64_t, 4 > dst_alloc = { 0 , 0 , 0 , 0 }) 3141: type_src ( type_src ), type_dst ( type_dst ), ne_src ( ne_src ), ne_dst ( ne_dst ), permute_src ( permute_src ), permute_dst ( permute_dst ), 3142dst_alloc ( dst_alloc ), 3143_src_use_permute ( permute_src [ 0 ] + permute_src [ 1 ] + permute_src [ 2 ] + permute_src [ 3 ] > 0 ), 3144_dst_use_permute ( permute_dst [ 0 ] + permute_dst [ 1 ] + permute_dst [ 2 ] + permute_dst [ 3 ] > 0 ), 3145_src_transpose ( transpose_src ), 3146_use_dst_shape ( ne_dst [ 0 ] >= 0 && ne_dst [ 1 ] >= 0 && ne_dst [ 2 ] >= 0 && ne_dst [ 3 ] >= 0 ), 3147_use_dst_alloc ( dst_alloc [ 0 ] > 0 ){} 3148 3149ggml_tensor * build_graph (ggml_context * ctx ) override { 3150ggml_tensor * src = ggml_new_tensor ( ctx , type_src , 4 , ne_src . data ()); 3151ggml_set_param ( src ); 3152ggml_set_name ( src , "src" ); 3153 3154if ( _src_use_permute ) { 3155src = ggml_permute ( ctx , src , permute_src [ 0 ], permute_src [ 1 ], permute_src [ 2 ], permute_src [ 3 ]); 3156ggml_set_name ( src , "src_permuted" ); 3157} 3158 3159if ( _src_transpose ) { 3160src = ggml_transpose ( ctx , src ); 3161ggml_set_name ( src , "src_transposed" ); 3162} 3163 3164std::array < int64_t, 4 > dst_ne = _use_dst_shape ? ne_dst : std::array < int64_t, 4 > { src -> ne [ 0 ], src -> ne [ 1 ], src -> ne [ 2 ], src -> ne [ 3 ]}; 3165ggml_tensor * dst ; 3166 3167if ( _use_dst_alloc ) { 3168// view a sub-block of a larger buffer -> strided dst 3169ggml_tensor * dst_buf = ggml_new_tensor ( ctx , type_dst , 4 , dst_alloc . data ()); 3170ggml_set_name ( dst_buf , "dst_buf" ); 3171dst = ggml_view_4d ( ctx , dst_buf , dst_ne [ 0 ], dst_ne [ 1 ], dst_ne [ 2 ], dst_ne [ 3 ], 3172dst_buf -> nb [ 1 ], dst_buf -> nb [ 2 ], dst_buf -> nb [ 3 ], 0 ); 3173ggml_set_name ( dst , "dst_view" ); 3174} else { 3175dst = ggml_new_tensor ( ctx , type_dst , 4 , dst_ne . data ()); 3176ggml_set_name ( dst , "dst" ); 3177 3178if ( _dst_use_permute ) { 3179dst = ggml_permute ( ctx , dst , permute_dst [ 0 ], permute_dst [ 1 ], permute_dst [ 2 ], permute_dst [ 3 ]); 3180ggml_set_name ( dst , "dst_permuted" ); 3181} 3182} 3183 3184ggml_tensor * out = ggml_cpy ( ctx , src , dst ); 3185ggml_set_name ( out , "out" ); 3186 3187return out ; 3188} 3189 3190void initialize_tensors (ggml_context * ctx ) override { 3191for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3192// test extended range of values to check if casting between f32 and i32 is consistent 3193init_tensor_uniform ( t , -150.f , 150.f ); 3194} 3195} 3196}; 3197 3198// GGML_OP_CONT 3199// permute = {0, 0, 0, 0} means no permutation: the source is transposed (or 3200// view-sliced). A non-identity permute applies ggml_permute before ggml_cont. 3201struct test_cont : public test_case { 3202const ggml_type type ; 3203const std::array < int64_t, 4 > ne ; 3204bool use_view_slice ; 3205const std::array < int64_t, 4 > permute ; 3206 3207std::string vars () override { 3208return VARS_TO_STR4 ( type , ne , use_view_slice , permute ); 3209} 3210 3211test_cont (ggml_type type = GGML_TYPE_F32 , 3212std::array < int64_t, 4 > ne = { 10 , 10 , 10 , 1 }, 3213bool use_view_slice = false, 3214std::array < int64_t, 4 > permute = { 0 , 0 , 0 , 0 }) 3215: type ( type ), ne ( ne ), use_view_slice ( use_view_slice ), permute ( permute ) {} 3216 3217ggml_tensor * build_graph (ggml_context * ctx ) override { 3218ggml_tensor * src = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3219ggml_set_param ( src ); 3220ggml_set_name ( src , "src" ); 3221 3222const bool permuted = permute [ 0 ] != 0 || permute [ 1 ] != 0 || permute [ 2 ] != 0 || permute [ 3 ] != 0 ; 3223 3224ggml_tensor * dst ; 3225if ( permuted ) { 3226dst = ggml_permute ( ctx , src , permute [ 0 ], permute [ 1 ], permute [ 2 ], permute [ 3 ]); 3227ggml_set_name ( dst , "src_permuted" ); 3228} else if ( use_view_slice ) { 3229dst = ggml_view_4d ( ctx , src , src -> ne [ 0 ], 1 , src -> ne [ 2 ], src -> ne [ 3 ], 3230src -> nb [ 1 ], src -> nb [ 2 ], src -> nb [ 3 ], src -> nb [ 0 ] * ( src -> ne [ 1 ] - 1 )); 3231ggml_set_name ( dst , "src_view_slice" ); 3232} else { 3233dst = ggml_transpose ( ctx , src ); 3234ggml_set_name ( dst , "src_transposed" ); 3235} 3236 3237ggml_tensor * out = ggml_cont ( ctx , dst ); 3238ggml_set_name ( out , "out" ); 3239 3240return out ; 3241} 3242}; 3243 3244// GGML_OP_ADD 3245// GGML_OP_SUB 3246// GGML_OP_MUL 3247// GGML_OP_DIV 3248struct test_bin_bcast : public test_case { 3249using op_t = ggml_tensor * ( * ) (ggml_context * , ggml_tensor * , ggml_tensor * ); 3250op_t op ; 3251const ggml_type type ; 3252const std::array < int64_t, 4 > ne ; 3253const std::array < int, 4 > nr ; 3254int nf ; // number of fused ops, nf == 1 -> single op (no fusion) 3255bool perm1 ; // permute src1? 3256bool src_overlap ; // src0 and src1 are overlapping views of the same buffer 3257 3258bool run_whole_graph () override { return nf > 1 ; } 3259 3260std::string vars () override { 3261return VARS_TO_STR6 ( type , ne , nr , nf , perm1 , src_overlap ); 3262} 3263 3264size_t op_size (ggml_tensor * t ) override { 3265return ggml_nbytes ( t ) * 3 ; 3266} 3267 3268test_bin_bcast (op_t op , ggml_type type = GGML_TYPE_F32 , 3269std::array < int64_t, 4 > ne = { 10 , 10 , 1 , 1 }, 3270std::array < int, 4 > nr = { 1 , 2 , 1 , 1 }, 3271int nf = 1 , 3272bool perm1 = false, bool src_overlap = false) 3273: op ( op ), type ( type ), ne ( ne ), nr ( nr ), nf ( nf ), perm1 ( perm1 ), src_overlap ( src_overlap ) {} 3274 3275ggml_tensor * build_graph (ggml_context * ctx ) override { 3276GGML_ASSERT ( nf <= 16 ); 3277 3278ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ] * nr [ 0 ], ne [ 1 ] * nr [ 1 ], ne [ 2 ] * nr [ 2 ], ne [ 3 ] * nr [ 3 ]); 3279ggml_set_name ( a , "a" ); 3280 3281ggml_tensor * b [ 16 ]; 3282for (int i = 0 ; i < nf ; ++ i ) { 3283if ( perm1 ) { 3284const int p [ 4 ] = { 1 , 2 , 0 , 3 }; // hardcoded for now 3285 3286b [ i ] = ggml_new_tensor_4d ( ctx , type , ne [ p [ 0 ]], ne [ p [ 1 ]], ne [ p [ 2 ]], ne [ p [ 3 ]]); 3287b [ i ] = ggml_permute ( ctx , b [ i ], p [ 0 ], p [ 1 ], p [ 2 ], p [ 3 ]); 3288} else if ( src_overlap ) { 3289b [ i ] = ggml_view_4d ( ctx , a , ne [ 0 ], ne [ 1 ], ne [ 2 ], 2 * ( ne [ 3 ] / 3 ), a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], ( ne [ 3 ] / 3 ) * a -> nb [ 3 ]); 3290} else { 3291b [ i ] = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3292} 3293ggml_set_name ( b [ i ], (std:: string ( "b" ) + std:: to_string ( i )). c_str ()); 3294} 3295 3296// The backward pass supports broadcasting only for GGML_ADD: 3297const bool grad_supported = op == ggml_add && ggml_are_same_shape ( a , b [ 0 ]) && nf == 1 && ! perm1 ; 3298if ( grad_supported ) { 3299ggml_set_param ( a ); 3300ggml_set_param ( b [ 0 ]); 3301} 3302 3303ggml_tensor * out ; 3304 3305if ( src_overlap ) { 3306out = ggml_view_4d ( ctx , a , ne [ 0 ], ne [ 1 ], ne [ 2 ], 2 * ( ne [ 3 ] / 3 ), a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 3307} else { 3308out = a ; 3309} 3310 3311for (int i = 0 ; i < nf ; ++ i ) { 3312out = op ( ctx , out , b [ i ]); 3313} 3314 3315ggml_set_name ( out , "out" ); 3316 3317return out ; 3318} 3319 3320void initialize_tensors (ggml_context * ctx ) override { 3321for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3322if ( op == ggml_mul || op == ggml_div ) { 3323// MUL and DIV have numerical issues around zero: 3324init_tensor_uniform ( t , 0.9f , 1.1f ); 3325} else { 3326init_tensor_uniform ( t ); 3327} 3328} 3329} 3330 3331float grad_eps () override { 3332return 0.1f * ( op == ggml_mul ? ne [ 0 ] * ne [ 1 ] * ne [ 2 ] * ne [ 3 ] : 1 ); 3333} 3334 3335bool grad_precise () override { 3336return op == ggml_div ; 3337} 3338 3339double max_nmse_err () override { 3340if ( op == ggml_add && type == GGML_TYPE_F16 && nf > 1 ) { 3341// Fused ADDs can keep FP32 intermediates while the CPU rounds each ADD to FP16. 3342return 1e-6 ; 3343} 3344return test_case:: max_nmse_err (); 3345} 3346 3347double max_maa_err () override { 3348return op == ggml_add ? 1e-4 : 1e-3 ; 3349} 3350}; 3351 3352// GGML_OP_ADD_ID 3353struct test_add_id : public test_case { 3354const ggml_type type_a ; 3355const ggml_type type_b ; 3356const int64_t n_embd ; 3357const int64_t n_experts ; 3358const int64_t n_experts_used ; 3359const int64_t n_token ; 3360 3361std::string vars () override { 3362return VARS_TO_STR6 ( type_a , type_b , n_embd , n_experts , n_experts_used , n_token ); 3363} 3364 3365size_t op_size (ggml_tensor * t ) override { 3366return ggml_nbytes ( t ) + ggml_nbytes ( t -> src [ 0 ]) + ggml_nbytes ( t -> src [ 2 ]); 3367} 3368 3369test_add_id (ggml_type type_a = GGML_TYPE_F32 , 3370ggml_type type_b = GGML_TYPE_F32 , 3371int64_t n_embd = 128 , 3372int64_t n_experts = 16 , 3373int64_t n_experts_used = 8 , 3374int64_t n_token = 10 ) 3375: type_a ( type_a ), type_b ( type_b ), n_embd ( n_embd ), 3376n_experts ( n_experts ), n_experts_used ( n_experts_used ), n_token ( n_token ) {} 3377 3378ggml_tensor * build_graph (ggml_context * ctx ) override { 3379ggml_tensor * a = ggml_new_tensor_3d ( ctx , type_a , n_embd , n_experts_used , n_token ); 3380ggml_tensor * b = ggml_new_tensor_2d ( ctx , type_b , n_embd , n_experts ); 3381ggml_tensor * ids = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , n_experts , n_token ); 3382if ( n_experts_used != n_experts ) { 3383ids = ggml_view_2d ( ctx , ids , n_experts_used , n_token , ids -> nb [ 1 ], 0 ); 3384ggml_set_name ( ids , "view_of_ids" ); 3385} 3386 3387ggml_tensor * out = ggml_add_id ( ctx , a , b , ids ); 3388ggml_set_name ( out , "out" ); 3389return out ; 3390} 3391 3392void initialize_tensors (ggml_context * ctx ) override { 3393for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3394if ( t -> type == GGML_TYPE_I32 ) { 3395if ( ggml_is_view_op ( t -> op )) { continue ; } 3396std::random_device rd ; 3397std::default_random_engine rng ( rd ()); 3398// ids 3399for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 3400std::vector < int32_t > data ( t -> ne [ 0 ]); 3401for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 3402data [ i ] = i % n_experts ; 3403} 3404std:: shuffle ( data . begin (), data . end (), rng ); 3405ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 3406} 3407} else { 3408init_tensor_uniform ( t ); 3409} 3410} 3411} 3412}; 3413 3414// GGML_OP_SCALE 3415struct test_scale : public test_case { 3416const ggml_type type ; 3417const std::array < int64_t, 4 > ne ; 3418float scale ; 3419float bias ; 3420bool inplace ; 3421 3422std::string vars () override { 3423return VARS_TO_STR5 ( type , ne , scale , bias , inplace ); 3424} 3425 3426test_scale (ggml_type type = GGML_TYPE_F32 , 3427std::array < int64_t, 4 > ne = { 10 , 10 , 10 , 10 }, 3428float scale = 2.0f , 3429float bias = 0.0f , 3430bool inplace = false) 3431: type ( type ), ne ( ne ), scale ( scale ), bias ( bias ), inplace ( inplace ) {} 3432 3433ggml_tensor * build_graph (ggml_context * ctx ) override { 3434ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3435ggml_set_param ( a ); 3436ggml_set_name ( a , "a" ); 3437 3438ggml_tensor * out ; 3439if ( inplace ) { 3440out = ggml_scale_bias_inplace ( ctx , a , scale , bias ); 3441} else { 3442out = ggml_scale_bias ( ctx , a , scale , bias ); 3443} 3444ggml_set_name ( out , "out" ); 3445 3446return out ; 3447} 3448}; 3449 3450// GGML_OP_SCALE + GGML_UNARY_OP_TANH + GGML_OP_SCALE 3451struct test_softcap : public test_case { 3452const ggml_type type ; 3453const std::array < int64_t, 4 > ne ; 3454float softcap ; 3455 3456std::string op_desc (ggml_tensor * t ) override { 3457GGML_UNUSED ( t ); 3458return "SOFTCAP" ; 3459} 3460 3461bool run_whole_graph () override { return true; } 3462 3463std::string vars () override { 3464return VARS_TO_STR3 ( type , ne , softcap ); 3465} 3466 3467test_softcap (ggml_type type = GGML_TYPE_F32 , 3468std::array < int64_t, 4 > ne = { 10 , 10 , 10 , 10 }, 3469float softcap = 30.0f ) 3470: type ( type ), ne ( ne ), softcap ( softcap ) {} 3471 3472ggml_tensor * build_graph (ggml_context * ctx ) override { 3473ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3474 3475ggml_set_param ( a ); 3476ggml_set_name ( a , "a" ); 3477 3478ggml_tensor * out = ggml_scale ( ctx , ggml_tanh ( ctx , ggml_scale ( ctx , a , 1.0f / softcap )), softcap ); 3479ggml_set_name ( out , "out" ); 3480 3481return out ; 3482} 3483}; 3484 3485// GGML_OP_SILU_BACK 3486struct test_silu_back : public test_case { 3487const ggml_type type ; 3488const std::array < int64_t, 4 > ne ; 3489float eps ; 3490 3491std::string vars () override { 3492return VARS_TO_STR3 ( type , ne , eps ); 3493} 3494 3495test_silu_back (ggml_type type = GGML_TYPE_F32 , 3496std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3497float eps = 1e-6f ) 3498: type ( type ), ne ( ne ), eps ( eps ) {} 3499 3500ggml_tensor * build_graph (ggml_context * ctx ) override { 3501ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3502ggml_set_name ( a , "a" ); 3503 3504ggml_tensor * grad = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3505ggml_set_name ( grad , "grad" ); 3506 3507ggml_tensor * out = ggml_silu_back ( ctx , a , grad ); 3508ggml_set_name ( out , "out" ); 3509 3510return out ; 3511} 3512 3513bool grad_precise () override { 3514return true; 3515} 3516}; 3517 3518// GGML_OP_NORM 3519struct test_norm : public test_case { 3520const ggml_type type ; 3521const std::array < int64_t, 4 > ne ; 3522const bool v ; // whether a is a non-contiguous view 3523const float eps ; 3524const bool noncontig_rows ; 3525 3526std::string vars () override { 3527return VARS_TO_STR5 ( type , ne , v , eps , noncontig_rows ); 3528} 3529 3530test_norm (ggml_type type = GGML_TYPE_F32 , 3531std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3532bool v = false, 3533float eps = 1e-6f , 3534bool noncontig_rows = false) 3535: type ( type ), ne ( ne ), v ( v ), eps ( eps ), noncontig_rows ( noncontig_rows ) {} 3536 3537ggml_tensor * build_graph (ggml_context * ctx ) override { 3538const std::array < int64_t, 4 > ne_a = noncontig_rows ? 3539std::array < int64_t, 4 > { ne [ 1 ], ne [ 0 ], ne [ 2 ], ne [ 3 ] } : ne ; 3540ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 3541ggml_set_name ( a , "a" ); 3542 3543if ( noncontig_rows ) { 3544a = ggml_permute ( ctx , a , 1 , 0 , 2 , 3 ); 3545ggml_set_name ( a , "permuted a" ); 3546} 3547if ( v ) { 3548a = ggml_view_4d ( ctx , a , a -> ne [ 0 ]/ 2 , a -> ne [ 1 ]/ 2 , a -> ne [ 2 ]/ 2 , a -> ne [ 3 ]/ 2 , a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 3549ggml_set_name ( a , "view of a" ); 3550} 3551 3552ggml_tensor * out = ggml_norm ( ctx , a , eps ); 3553ggml_set_name ( out , "out" ); 3554 3555return out ; 3556} 3557}; 3558 3559// GGML_OP_NORM + GGML_OP_MUL + GGML_OP_ADD 3560struct test_norm_mul_add : public test_case { 3561const ggml_type type ; 3562const std::array < int64_t, 4 > ne ; 3563float eps ; 3564const bool broadcast ; 3565 3566std::string op_desc (ggml_tensor * t ) override { 3567GGML_UNUSED ( t ); 3568return "NORM_MUL_ADD" ; 3569} 3570 3571bool run_whole_graph () override { return true; } 3572 3573std::string vars () override { 3574return VARS_TO_STR4 ( type , ne , eps , broadcast ); 3575} 3576 3577test_norm_mul_add (ggml_type type = GGML_TYPE_F32 , 3578std::array < int64_t, 4 > ne = { 128 , 2 , 1 , 1 }, 3579float eps = 1e-5f , 3580bool broadcast = false) 3581: type ( type ), ne ( ne ), eps ( eps ), broadcast ( broadcast ) {} 3582 3583ggml_tensor * build_graph (ggml_context * ctx ) override { 3584std::array < int64_t, 4 > broadcast_dims = { ne [ 0 ], ne [ 1 ] * 2 , ne [ 2 ] * 2 , ne [ 3 ] * 2 }; 3585 3586ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , broadcast ? broadcast_dims . data () : ne . data ()); 3587ggml_tensor * w = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3588ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3589ggml_set_param ( a ); ggml_set_param ( w ); ggml_set_param ( b ); 3590ggml_set_name ( a , "a" ); ggml_set_name ( w , "w" ); ggml_set_name ( b , "b" ); 3591 3592// Use a, w and b early to avoid OP_NONE in graph 3593a = ggml_add ( ctx , ggml_add ( ctx , a , w ), b ); 3594 3595ggml_tensor * n = ggml_norm ( ctx , a , eps ); 3596ggml_tensor * m = ggml_mul ( ctx , n , w ); 3597ggml_tensor * out = ggml_add ( ctx , m , b ); 3598ggml_set_name ( out , "out" ); 3599return out ; 3600} 3601}; 3602// GGML_OP_RMS_NORM 3603struct test_rms_norm : public test_case { 3604const ggml_type type ; 3605const std::array < int64_t, 4 > ne ; 3606const bool v ; // whether a is a non-contiguous view 3607const float eps ; 3608const bool inplace ; // whether to do the operation inplace 3609 3610std::string vars () override { 3611return VARS_TO_STR5 ( type , ne , v , eps , inplace ); 3612} 3613 3614test_rms_norm (ggml_type type = GGML_TYPE_F32 , 3615std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3616bool v = false, 3617float eps = 1e-6f , 3618bool inplace = false) 3619: type ( type ), ne ( ne ), v ( v ), eps ( eps ), inplace ( inplace ) {} 3620 3621ggml_tensor * build_graph (ggml_context * ctx ) override { 3622ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3623ggml_set_param ( a ); 3624ggml_set_name ( a , "a" ); 3625 3626if ( v ) { 3627a = ggml_view_4d ( ctx , a , a -> ne [ 0 ]/ 2 , a -> ne [ 1 ]/ 2 , a -> ne [ 2 ]/ 2 , a -> ne [ 3 ]/ 2 , a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 3628ggml_set_name ( a , "view of a" ); 3629} 3630 3631ggml_tensor * out ; 3632if ( inplace ) { 3633out = ggml_rms_norm_inplace ( ctx , a , eps ); 3634} else { 3635out = ggml_rms_norm ( ctx , a , eps ); 3636} 3637ggml_set_name ( out , "out" ); 3638 3639return out ; 3640} 3641 3642void initialize_tensors (ggml_context * ctx ) override { 3643for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3644init_tensor_uniform ( t , -10.f , 10.f ); 3645} 3646} 3647 3648float grad_eps () override { 3649return 1.0f ; 3650} 3651 3652bool grad_precise () override { 3653return true; 3654} 3655}; 3656 3657// GGML_OP_RMS_NORM_BACK 3658struct test_rms_norm_back : public test_case { 3659const ggml_type type ; 3660const std::array < int64_t, 4 > ne ; 3661const float eps ; 3662 3663std::string vars () override { 3664return VARS_TO_STR3 ( type , ne , eps ); 3665} 3666 3667test_rms_norm_back (ggml_type type = GGML_TYPE_F32 , 3668std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3669float eps = 1e-6f ) 3670: type ( type ), ne ( ne ), eps ( eps ) {} 3671 3672ggml_tensor * build_graph (ggml_context * ctx ) override { 3673ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3674ggml_set_name ( a , "a" ); 3675 3676ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3677ggml_set_name ( b , "b" ); 3678 3679ggml_tensor * out = ggml_rms_norm_back ( ctx , a , b , eps ); 3680ggml_set_name ( out , "out" ); 3681 3682return out ; 3683} 3684 3685void initialize_tensors (ggml_context * ctx ) override { 3686for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3687init_tensor_uniform ( t , -10.f , 10.f ); 3688} 3689} 3690}; 3691 3692// GGML_OP_RMS_NORM + GGML_OP_MUL + GGML_OP_ADD (+ GGML_OP_MUL) 3693struct test_rms_norm_mul_add : public test_case { 3694const ggml_type type ; 3695const std::array < int64_t, 4 > ne ; 3696const float eps ; 3697const bool broadcast ; 3698const bool multi_add ; // test a sequence of adds feeding into rms_norm 3699const bool post_mul ; 3700const bool alias_rms_input ; 3701const bool weight_broadcast ; 3702 3703std::string op_desc (ggml_tensor * t ) override { 3704GGML_UNUSED ( t ); 3705return "RMS_NORM_MUL_ADD" ; 3706} 3707 3708bool run_whole_graph () override { return true; } 3709 3710std::string vars () override { 3711return VARS_TO_STR8 ( type , ne , eps , broadcast , multi_add , post_mul , alias_rms_input , weight_broadcast ); 3712} 3713 3714test_rms_norm_mul_add (ggml_type type = GGML_TYPE_F32 , 3715std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3716float eps = 1e-6f , bool broadcast = false, bool multi_add = false, bool post_mul = false, 3717bool alias_rms_input = false, bool weight_broadcast = false) 3718: type ( type ), ne ( ne ), eps ( eps ), broadcast ( broadcast ), multi_add ( multi_add ), post_mul ( post_mul ), 3719alias_rms_input ( alias_rms_input ), weight_broadcast ( weight_broadcast ) {} 3720 3721ggml_tensor * build_graph (ggml_context * ctx ) override { 3722std::array < int64_t, 4 > broadcast_dims = { ne [ 0 ] * 2 , ne [ 1 ] * 3 , ne [ 2 ] * 3 , ne [ 3 ] * 4 }; 3723 3724ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , broadcast ? broadcast_dims . data () : ne . data ()); 3725ggml_tensor * b = weight_broadcast ? ggml_new_tensor_1d ( ctx , type , ne [ 0 ]) : ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3726ggml_tensor * c = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3727ggml_tensor * d = nullptr ; 3728 3729ggml_set_param ( a ); 3730ggml_set_name ( a , "a" ); 3731ggml_set_param ( b ); 3732ggml_set_name ( b , "b" ); 3733ggml_set_param ( c ); 3734ggml_set_name ( c , "c" ); 3735 3736// Use a, b and c early, so we don't end up with an OP_NONE between rms_norm and mul 3737a = ggml_add ( ctx , ggml_add ( ctx , a , b ), c ); 3738if ( post_mul ) { 3739d = ggml_new_tensor_1d ( ctx , type , 1 ); 3740ggml_set_param ( d ); 3741ggml_set_name ( d , "d" ); 3742a = ggml_add ( ctx , a , d ); 3743} 3744if ( multi_add ) { 3745a = ggml_add ( ctx , ggml_add ( ctx , a , b ), c ); 3746} 3747ggml_tensor * mul = ggml_mul ( ctx , ggml_rms_norm ( ctx , a , eps ), b ); 3748ggml_tensor * out = alias_rms_input ? ggml_add_inplace ( ctx , a , mul ) : ggml_add ( ctx , mul , c ); 3749if ( post_mul ) { 3750out = ggml_mul ( ctx , out , d ); 3751} 3752ggml_set_name ( out , "out" ); 3753 3754return out ; 3755} 3756 3757void initialize_tensors (ggml_context * ctx ) override { 3758for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3759init_tensor_uniform ( t , -10.f , 10.f ); 3760} 3761} 3762 3763float grad_eps () override { 3764return 1.0f ; 3765} 3766 3767bool grad_precise () override { 3768return true; 3769} 3770}; 3771 3772// GGML_OP_ADD + GGML_OP_ADD (fused residual chain) 3773struct test_add_add : public test_case { 3774const ggml_type type ; 3775const ggml_type type_addend ; 3776const std::array < int64_t, 4 > ne ; 3777const bool broadcast ; 3778const bool view ; // non-contiguous a via view_4d 3779 3780std::string op_desc (ggml_tensor * t ) override { 3781GGML_UNUSED ( t ); 3782return "ADD_ADD" ; 3783} 3784 3785bool run_whole_graph () override { return true; } 3786 3787std::string vars () override { 3788return VARS_TO_STR5 ( type , type_addend , ne , broadcast , view ); 3789} 3790 3791test_add_add (ggml_type type = GGML_TYPE_F32 , 3792ggml_type type_addend = GGML_TYPE_F32 , 3793std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3794bool broadcast = false, 3795bool view = false) 3796: type ( type ), type_addend ( type_addend ), ne ( ne ), broadcast ( broadcast ), view ( view ) {} 3797 3798ggml_tensor * build_graph (ggml_context * ctx ) override { 3799std::array < int64_t, 4 > broadcast_dims = { ne [ 0 ], 1 , 1 , 1 }; 3800 3801ggml_tensor * a ; 3802if ( view ) { 3803std::array < int64_t, 4 > parent = { ne [ 0 ] * 3 , ne [ 1 ] * 2 , ne [ 2 ], ne [ 3 ] }; 3804a = ggml_new_tensor ( ctx , type , 4 , parent . data ()); 3805ggml_set_name ( a , "a_parent" ); 3806a = ggml_view_4d ( ctx , a , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 3807ggml_set_name ( a , "a" ); 3808} else { 3809a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3810ggml_set_name ( a , "a" ); 3811} 3812 3813ggml_tensor * b = ggml_new_tensor ( ctx , type_addend , 4 , ne . data ()); 3814ggml_tensor * c = ggml_new_tensor ( ctx , type_addend , 4 , broadcast ? broadcast_dims . data () : ne . data ()); 3815 3816ggml_set_name ( b , "b" ); 3817ggml_set_name ( c , "c" ); 3818 3819ggml_tensor * out = ggml_add ( ctx , ggml_add ( ctx , a , b ), c ); 3820ggml_set_name ( out , "out" ); 3821 3822return out ; 3823} 3824}; 3825 3826// GGML_OP_ADD + GGML_OP_RMS_NORM (fused operation) 3827struct test_add_rms_norm : public test_case { 3828const ggml_type type ; 3829const std::array < int64_t, 4 > ne ; 3830const float eps ; 3831const bool broadcast ; 3832 3833std::string op_desc (ggml_tensor * t ) override { 3834GGML_UNUSED ( t ); 3835return "ADD_RMS_NORM" ; 3836} 3837 3838bool run_whole_graph () override { return true; } 3839 3840std::string vars () override { 3841return VARS_TO_STR4 ( type , ne , eps , broadcast ); 3842} 3843 3844test_add_rms_norm (ggml_type type = GGML_TYPE_F32 , 3845std::array < int64_t, 4 > ne = { 64 , 5 , 4 , 3 }, 3846float eps = 1e-6f , bool broadcast = false) 3847: type ( type ), ne ( ne ), eps ( eps ), broadcast ( broadcast ) {} 3848 3849ggml_tensor * build_graph (ggml_context * ctx ) override { 3850std::array < int64_t, 4 > broadcast_dims = { ne [ 0 ] * 2 , ne [ 1 ] * 3 , ne [ 2 ] * 3 , ne [ 3 ] * 4 }; 3851 3852ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , broadcast ? broadcast_dims . data () : ne . data ()); 3853ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3854 3855ggml_set_param ( a ); 3856ggml_set_name ( a , "a" ); 3857ggml_set_param ( b ); 3858ggml_set_name ( b , "b" ); 3859 3860// ADD operation followed by RMS_NORM 3861ggml_tensor * add_result = ggml_add ( ctx , a , b ); 3862ggml_set_name ( add_result , "add_result" ); 3863 3864ggml_tensor * out = ggml_rms_norm ( ctx , add_result , eps ); 3865ggml_set_name ( out , "out" ); 3866 3867return out ; 3868} 3869 3870void initialize_tensors (ggml_context * ctx ) override { 3871for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 3872init_tensor_uniform ( t , -10.f , 10.f ); 3873} 3874} 3875 3876float grad_eps () override { 3877return 1.0f ; 3878} 3879 3880bool grad_precise () override { 3881return true; 3882} 3883}; 3884 3885// GGML_OP_UNARY(RELU) + GGML_OP_SQR (fused operation) 3886struct test_relu_sqr : public test_case { 3887const ggml_type type ; 3888const std::array < int64_t, 4 > ne ; 3889 3890std::string op_desc (ggml_tensor * t ) override { 3891GGML_UNUSED ( t ); 3892return "RELU_SQR" ; 3893} 3894 3895bool run_whole_graph () override { return true; } 3896 3897std::string vars () override { 3898return VARS_TO_STR2 ( type , ne ); 3899} 3900 3901test_relu_sqr (ggml_type type = GGML_TYPE_F32 , 3902std::array < int64_t, 4 > ne = { 128 , 2 , 2 , 2 }) 3903: type ( type ), ne ( ne ) {} 3904 3905ggml_tensor * build_graph (ggml_context * ctx ) override { 3906ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3907ggml_set_name ( a , "a" ); 3908 3909ggml_tensor * r = ggml_relu ( ctx , a ); 3910ggml_set_name ( r , "relu" ); 3911 3912ggml_tensor * out = ggml_sqr ( ctx , r ); 3913ggml_set_name ( out , "out" ); 3914 3915return out ; 3916} 3917}; 3918 3919// GGML_OP_UNARY(GELU|SILU|SIGMOID|SOFTPLUS) + GGML_OP_MUL (fused operation). 3920struct test_unary_mul : public test_case { 3921const ggml_unary_op op ; 3922const ggml_type type ; 3923const std::array < int64_t, 4 > ne ; 3924const bool swap ; // unary result is the second MUL operand 3925const std::string layout ; // operand layout, see build_graph() 3926const std::string tail ; // extra consumer past the MUL, see build_graph() 3927 3928std::string op_desc (ggml_tensor * t ) override { 3929GGML_UNUSED ( t ); 3930return std:: string ( ggml_unary_op_name ( op )) + "_MUL" ; 3931} 3932 3933bool run_whole_graph () override { return true; } 3934 3935double max_nmse_err () override { 3936// the fused kernel elides the rounding of the unary result that the CPU chain 3937// performs; relax the tolerance to match that drift 3938switch ( type ) { 3939case GGML_TYPE_F16 : return 5e-5 ; 3940// gelu shader uses exp form, CPU uses tanhf 3941default : return op == GGML_UNARY_OP_GELU ? 5e-7 : 1e-7 ; 3942} 3943} 3944 3945std::string vars () override { 3946return VARS_TO_STR5 ( type , ne , swap , layout , tail ); 3947} 3948 3949test_unary_mul (ggml_unary_op op , 3950ggml_type type = GGML_TYPE_F32 , 3951std::array < int64_t, 4 > ne = { 128 , 2 , 2 , 2 }, 3952bool swap = false, 3953std::string layout = "packed" , 3954std::string tail = "" ) 3955: op ( op ), type ( type ), ne ( ne ), swap ( swap ), layout (std:: move ( layout )), tail (std:: move ( tail )) {} 3956 3957// `ne` viewed out of a wider tensor: rows stay contiguous, but the stride exceeds the width 3958ggml_tensor * padded (ggml_context * ctx , const char * name , int64_t mul0 , int64_t off0 ) { 3959std::array < int64_t, 4 > ne_w = ne ; 3960ne_w [ 0 ] *= mul0 ; 3961ggml_tensor * base = ggml_new_tensor ( ctx , type , 4 , ne_w . data ()); 3962ggml_set_name ( base , name ); 3963return ggml_view_4d ( ctx , base , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], 3964base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], off0 * base -> nb [ 0 ]); 3965} 3966 3967ggml_tensor * build_graph (ggml_context * ctx ) override { 3968ggml_tensor * a = nullptr ; // unary source 3969ggml_tensor * b = nullptr ; // other MUL operand 3970 3971if ( layout == "packed" ) { 3972a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3973b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3974} else if ( layout == "pad_unary" ) { 3975a = padded ( ctx , "a" , 3 , 0 ); 3976b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3977} else if ( layout == "pad_other" ) { 3978a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3979b = padded ( ctx , "b" , 3 , 0 ); 3980} else if ( layout == "halves" ) { 3981// the shape the Conformer audio encoders build: one tensor split in two 3982std::array < int64_t, 4 > ne_w = ne ; 3983ne_w [ 0 ] *= 2 ; 3984ggml_tensor * base = ggml_new_tensor ( ctx , type , 4 , ne_w . data ()); 3985ggml_set_name ( base , "base" ); 3986b = ggml_view_4d ( ctx , base , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], 0 ); 3987a = ggml_view_4d ( ctx , base , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], 3988ne [ 0 ] * base -> nb [ 0 ]); 3989} else if ( layout == "strided_dim1" ) { 3990// contiguous rows but a strided dim 1: not ggml_is_contiguous_1, must not fuse 3991std::array < int64_t, 4 > ne_w = ne ; 3992ne_w [ 1 ] *= 3 ; 3993ggml_tensor * base = ggml_new_tensor ( ctx , type , 4 , ne_w . data ()); 3994ggml_set_name ( base , "a" ); 3995a = ggml_view_4d ( ctx , base , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], 0 ); 3996b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3997} else if ( layout == "bcast" ) { 3998a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 3999b = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], 1 , 1 , 1 ); 4000} else if ( layout == "rep_ne0" ) { 4001// repeat on dim 0 4002a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 4003std::array < int64_t, 4 > ne_b = ne ; 4004ne_b [ 0 ] /= 4 ; 4005b = ggml_new_tensor ( ctx , type , 4 , ne_b . data ()); 4006} else if ( layout == "view_mid" ) { 4007// VIEW between UNARY and MUL 4008a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 4009b = nullptr ; 4010} else if ( layout == "gate" ) { 4011// small gate on src1 4012const std::array < int64_t, 4 > ne_gate = { 1 , ne [ 1 ], ne [ 2 ], ne [ 3 ] }; 4013a = ggml_new_tensor ( ctx , type , 4 , ne_gate . data ()); 4014b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 4015} else { 4016GGML_ABORT ( "unknown layout %s" , layout . c_str ()); 4017} 4018if ( a != nullptr ) { 4019ggml_set_name ( a , "a" ); 4020} 4021if ( b != nullptr ) { 4022ggml_set_name ( b , "b" ); 4023} 4024 4025ggml_tensor * u = ggml_unary ( ctx , a , op ); 4026ggml_set_name ( u , "unary" ); 4027 4028// a broadcasting operand can only be the second one 4029const bool second = layout == "gate" || ( swap && layout != "bcast" && layout != "view_mid" ); 4030if ( layout == "view_mid" ) { 4031std::array < int64_t, 4 > ne_base = ne ; 4032ne_base [ 0 ] *= 2 ; 4033ggml_tensor * base = ggml_new_tensor ( ctx , type , 4 , ne_base . data ()); 4034ggml_set_name ( base , "base" ); 4035b = ggml_view_4d ( ctx , base , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], 4036base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], 0 ); 4037ggml_set_name ( b , "b" ); 4038} 4039ggml_tensor * out = second ? ggml_mul ( ctx , b , u ) : ggml_mul ( ctx , u , b ); 4040 4041if ( tail == "reuse" ) { 4042// a second read of the unary result must block the fusion 4043ggml_set_name ( out , "mul" ); 4044out = ggml_add ( ctx , out , u ); 4045} else if ( tail == "consumer" ) { 4046// fusion still applies; catches a dispatcher that skips one node too many 4047ggml_set_name ( out , "mul" ); 4048out = ggml_add ( ctx , out , b ); 4049} else if (! tail . empty ()) { 4050GGML_ABORT ( "unknown tail %s" , tail . c_str ()); 4051} 4052ggml_set_name ( out , "out" ); 4053 4054return out ; 4055} 4056}; 4057 4058// SNAKE activation fusion: y = x + sin(a*x)^2 * inv_b 4059// CUDA backend matches the naive 5-op chain (mul, sin, sqr, mul, add) 4060// and dispatches a single fused kernel. 4061struct test_snake_fuse : public test_case { 4062const ggml_type type ; 4063const std::array < int64_t, 4 > ne ; // [T, C, D2, D3] 4064 4065std::string op_desc (ggml_tensor * t ) override { 4066GGML_UNUSED ( t ); 4067return "SNAKE_FUSE" ; 4068} 4069 4070bool run_whole_graph () override { return true; } 4071 4072double max_nmse_err () override { 4073// BF16 epsilon ~ 7.8e-3, F16 epsilon ~ 9.7e-4: relax tolerance to match 4074// the natural roundoff drift between the naive CPU chain and the fused 4075// CUDA kernel. F32 keeps the default tight bound. 4076switch ( type ) { 4077case GGML_TYPE_BF16 : return 5e-3 ; 4078case GGML_TYPE_F16 : return 5e-5 ; 4079default : return 1e-7 ; 4080} 4081} 4082 4083std::string vars () override { 4084return VARS_TO_STR2 ( type , ne ); 4085} 4086 4087test_snake_fuse (ggml_type type = GGML_TYPE_F32 , 4088std::array < int64_t, 4 > ne = { 256 , 192 , 1 , 1 }) 4089: type ( type ), ne ( ne ) {} 4090 4091ggml_tensor * build_graph (ggml_context * ctx ) override { 4092ggml_tensor * x = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 4093ggml_set_name ( x , "x" ); 4094 4095ggml_tensor * a = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , 1 , ne [ 1 ]); 4096ggml_set_name ( a , "a" ); 4097 4098ggml_tensor * inv_b = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , 1 , ne [ 1 ]); 4099ggml_set_name ( inv_b , "inv_b" ); 4100 4101// exact 5-op chain that BigVGAN / Vocos frontends emit 4102ggml_tensor * ax = ggml_mul ( ctx , x , a ); 4103ggml_tensor * sin_ax = ggml_sin ( ctx , ax ); 4104ggml_tensor * sin_sq = ggml_sqr ( ctx , sin_ax ); 4105ggml_tensor * scaled = ggml_mul ( ctx , sin_sq , inv_b ); 4106ggml_tensor * out = ggml_add ( ctx , x , scaled ); 4107ggml_set_name ( out , "out" ); 4108 4109return out ; 4110} 4111 4112void initialize_tensors (ggml_context * ctx ) override { 4113// x in [-pi, pi] to exercise sin periodicity, params in default [-1, 1] 4114for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 4115const std::string name = ggml_get_name ( t ); 4116if ( name == "x" ) { 4117init_tensor_uniform ( t , -3.14159f , 3.14159f ); 4118} else { 4119init_tensor_uniform ( t ); 4120} 4121} 4122} 4123}; 4124 4125 4126struct test_dsv4_hc : public test_case { 4127static constexpr int64_t hc = 4 ; 4128 4129ggml_tensor * out = nullptr ; 4130 4131static uint32_t tensor_seed ( const ggml_tensor * t ) { 4132uint32_t seed = 2166136261u ; 4133for ( const char * p = ggml_get_name ( t ); * p ; ++ p ) { 4134seed ^= (uint8_t) * p ; 4135seed *= 16777619u ; 4136} 4137for (int i = 0 ; i < GGML_MAX_DIMS ; ++ i ) { 4138seed ^= (uint32_t) t -> ne [ i ]; 4139seed *= 16777619u ; 4140} 4141return seed ; 4142} 4143 4144static bool tensor_range ( const std::string & name , float & lo , float & hi ) { 4145if ( name == "mixes" ) { 4146lo = -2.0f ; hi = 2.0f ; return true; 4147} 4148if ( name == "scale" ) { 4149lo = -0.5f ; hi = 0.5f ; return true; 4150} 4151if ( name == "base" ) { 4152lo = -0.25f ; hi = 0.25f ; return true; 4153} 4154if ( name == "weights" || name == "comb" ) { 4155lo = 0.0f ; hi = 1.0f ; return true; 4156} 4157if ( name == "post" ) { 4158lo = 0.0f ; hi = 2.0f ; return true; 4159} 4160if ( name == "x" || name == "residual" ) { 4161lo = -1.0f ; hi = 1.0f ; return true; 4162} 4163return false; 4164} 4165 4166void initialize_tensors (ggml_context * ctx ) override { 4167for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 4168const std::string name = ggml_get_name ( t ); 4169float lo ; 4170float hi ; 4171if (! tensor_range ( name , lo , hi )) { 4172init_tensor_uniform ( t ); 4173continue ; 4174} 4175 4176GGML_ASSERT ( t -> type == GGML_TYPE_F32 ); 4177std::mt19937 rng ( tensor_seed ( t )); 4178std::uniform_real_distribution < float > dist (lo, hi); 4179std::vector < float > data ( ggml_nelements ( t )); 4180for (float & v : data ) { 4181v = dist ( rng ); 4182} 4183ggml_backend_tensor_set ( t , data . data (), 0 , data . size () * sizeof (float)); 4184} 4185} 4186}; 4187 4188struct test_dsv4_hc_comb : public test_dsv4_hc { 4189const int64_t n_tokens ; 4190const int32_t n_iter ; 4191const float eps ; 4192 4193std::string op_desc (ggml_tensor * t ) override { 4194GGML_UNUSED ( t ); 4195return "DSV4_HC_COMB" ; 4196} 4197 4198std::string vars () override { 4199return VARS_TO_STR3 ( n_tokens , n_iter , eps ); 4200} 4201 4202test_dsv4_hc_comb (int64_t n_tokens = 17 , int32_t n_iter = 4 , float eps = 1e-6f ) 4203: n_tokens ( n_tokens ), n_iter ( n_iter ), eps ( eps ) {} 4204 4205ggml_tensor * build_graph (ggml_context * ctx ) override { 4206ggml_tensor * mixes = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , ( 2 + hc ) * hc , n_tokens ); 4207ggml_set_name ( mixes , "mixes" ); 4208 4209ggml_tensor * scale = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , 3 ); 4210ggml_set_name ( scale , "scale" ); 4211 4212ggml_tensor * base = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , ( 2 + hc ) * hc ); 4213ggml_set_name ( base , "base" ); 4214 4215out = ggml_dsv4_hc_comb ( ctx , mixes , scale , base , eps , n_iter ); 4216ggml_set_name ( out , "out" ); 4217return out ; 4218} 4219}; 4220 4221struct test_dsv4_hc_pre : public test_dsv4_hc { 4222const int64_t n_embd ; 4223const int64_t n_tokens ; 4224 4225std::string op_desc (ggml_tensor * t ) override { 4226GGML_UNUSED ( t ); 4227return "DSV4_HC_PRE" ; 4228} 4229 4230std::string vars () override { 4231return VARS_TO_STR2 ( n_embd , n_tokens ); 4232} 4233 4234test_dsv4_hc_pre (int64_t n_embd = 31 , int64_t n_tokens = 17 ) 4235: n_embd ( n_embd ), n_tokens ( n_tokens ) {} 4236 4237ggml_tensor * build_graph (ggml_context * ctx ) override { 4238ggml_tensor * x = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , n_embd , hc , n_tokens ); 4239ggml_set_name ( x , "x" ); 4240 4241ggml_tensor * weights = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , hc , n_tokens ); 4242ggml_set_name ( weights , "weights" ); 4243 4244out = ggml_dsv4_hc_pre ( ctx , x , weights ); 4245ggml_set_name ( out , "out" ); 4246return out ; 4247} 4248}; 4249 4250struct test_dsv4_hc_post : public test_dsv4_hc { 4251const int64_t n_embd ; 4252const int64_t n_tokens ; 4253 4254std::string op_desc (ggml_tensor * t ) override { 4255GGML_UNUSED ( t ); 4256return "DSV4_HC_POST" ; 4257} 4258 4259std::string vars () override { 4260return VARS_TO_STR2 ( n_embd , n_tokens ); 4261} 4262 4263test_dsv4_hc_post (int64_t n_embd = 31 , int64_t n_tokens = 17 ) 4264: n_embd ( n_embd ), n_tokens ( n_tokens ) {} 4265 4266ggml_tensor * build_graph (ggml_context * ctx ) override { 4267ggml_tensor * x = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , n_embd , n_tokens ); 4268ggml_set_name ( x , "x" ); 4269 4270ggml_tensor * residual = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , n_embd , hc , n_tokens ); 4271ggml_set_name ( residual , "residual" ); 4272 4273ggml_tensor * post = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , hc , n_tokens ); 4274ggml_set_name ( post , "post" ); 4275 4276ggml_tensor * comb = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , hc , hc , n_tokens ); 4277ggml_set_name ( comb , "comb" ); 4278 4279out = ggml_dsv4_hc_post ( ctx , x , residual , post , comb ); 4280ggml_set_name ( out , "out" ); 4281return out ; 4282} 4283}; 4284 4285 4286// GGML_OP_SSM_CONV 4287struct test_ssm_conv : public test_case { 4288const ggml_type type ; 4289const std::array < int64_t, 4 > ne_a ; 4290const std::array < int64_t, 4 > ne_b ; 4291 4292std::string vars () override { 4293return VARS_TO_STR3 ( type , ne_a , ne_b ); 4294} 4295 4296test_ssm_conv (ggml_type type = GGML_TYPE_F32 , 4297std::array < int64_t, 4 > ne_a = { 10 , 10 , 10 , 1 }, 4298std::array < int64_t, 4 > ne_b = { 3 , 3 , 1 , 1 }) 4299: type ( type ), ne_a ( ne_a ), ne_b ( ne_b ) {} 4300 4301ggml_tensor * build_graph (ggml_context * ctx ) override { 4302ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 4303ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne_b . data ()); 4304ggml_tensor * out = ggml_ssm_conv ( ctx , a , b ); 4305return out ; 4306} 4307}; 4308 4309// GGML_OP_SSM_CONV + GGML_OP_ADD (channel-wise bias, optional) + GGML_OP_UNARY(SILU) (fused operation) 4310struct test_ssm_conv_bias_silu : public test_case { 4311const ggml_type type ; 4312const std::array < int64_t, 4 > ne_a ; 4313const std::array < int64_t, 4 > ne_b ; 4314const bool fuse_bias ; 4315 4316std::string op_desc (ggml_tensor * t ) override { 4317GGML_UNUSED ( t ); 4318return "SSM_CONV_BIAS_SILU" ; 4319} 4320 4321bool run_whole_graph () override { return true; } 4322 4323std::string vars () override { 4324return VARS_TO_STR4 ( type , ne_a , ne_b , fuse_bias ); 4325} 4326 4327test_ssm_conv_bias_silu (ggml_type type , std::array < int64_t, 4 > ne_a , std::array < int64_t, 4 > ne_b , 4328bool fuse_bias ) 4329: type ( type ), ne_a ( ne_a ), ne_b ( ne_b ), fuse_bias ( fuse_bias ) {} 4330 4331ggml_tensor * build_graph (ggml_context * ctx ) override { 4332ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 4333ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne_b . data ()); 4334ggml_set_name ( a , "a" ); 4335ggml_set_name ( b , "b" ); 4336 4337ggml_tensor * out = ggml_ssm_conv ( ctx , a , b ); 4338 4339if ( fuse_bias ) { 4340ggml_tensor * bias = ggml_new_tensor_1d ( ctx , type , out -> ne [ 0 ]); 4341ggml_set_name ( bias , "bias" ); 4342out = ggml_add ( ctx , out , bias ); 4343} 4344 4345out = ggml_silu ( ctx , out ); 4346 4347ggml_set_name ( out , "out" ); 4348return out ; 4349} 4350}; 4351 4352// GGML_OP_SSM_SCAN 4353struct test_ssm_scan : public test_case { 4354const ggml_type type ; 4355 4356const int64_t d_state ; 4357const int64_t head_dim ; 4358const int64_t n_head ; 4359const int64_t n_group ; 4360const int64_t n_seq_tokens ; 4361const int64_t n_seqs ; 4362const bool xbc_overlap ; 4363const int64_t K ; 4364const bool weak_decay ; 4365 4366std::string vars () override { 4367return VARS_TO_STR10 ( type , d_state , head_dim , n_head , n_group , n_seq_tokens , n_seqs , xbc_overlap , K , weak_decay ); 4368} 4369 4370test_ssm_scan (ggml_type type = GGML_TYPE_F32 , 4371int64_t d_state = 32 , 4372int64_t head_dim = 1 , // 1 = Mamba-1; > 1 = Mamba-2 (scalar A per head) 4373int64_t n_head = 32 , 4374int64_t n_group = 1 , 4375int64_t n_seq_tokens = 32 , 4376int64_t n_seqs = 32 , 4377bool xbc_overlap = false, 4378int64_t K = 1 , 4379bool weak_decay = false) 4380: type ( type ), d_state ( d_state ), head_dim ( head_dim ), n_head ( n_head ), n_group ( n_group ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ), xbc_overlap ( xbc_overlap ), K ( K ), weak_decay ( weak_decay ) {} 4381 4382double max_nmse_err () override { 4383// SSD path (head_dim > 1) uses FP16 intermediates (M matrix, X_dt); Mamba-1 is pure FP32. 4384return ( head_dim > 1 ) ? 2e-7 : 1e-7 ; 4385} 4386 4387ggml_tensor * build_graph (ggml_context * ctx ) override { 4388ggml_tensor * s = ggml_new_tensor_4d ( ctx , type , d_state , head_dim , n_head , n_seqs ); 4389ggml_tensor * dt = ggml_new_tensor_3d ( ctx , type , n_head , n_seq_tokens , n_seqs ); 4390ggml_tensor * A = ggml_new_tensor_2d ( ctx , type , ( head_dim > 1 ) ? 1 : d_state , n_head ); 4391ggml_tensor * x ; 4392ggml_tensor * B ; 4393ggml_tensor * C ; 4394 4395if ( xbc_overlap ) { 4396ggml_tensor * xbc = ggml_new_tensor_4d ( ctx , type , d_state , n_head , n_seq_tokens , 2 * n_seqs ); 4397x = ggml_view_4d ( ctx , xbc , head_dim , n_head , n_seq_tokens , n_seqs , 4398xbc -> nb [ 1 ], xbc -> nb [ 2 ], xbc -> nb [ 3 ], xbc -> nb [ 3 ]); 4399B = ggml_view_4d ( ctx , xbc , d_state , n_group , n_seq_tokens , n_seqs , 4400xbc -> nb [ 1 ], xbc -> nb [ 2 ], xbc -> nb [ 3 ], 0 ); 4401C = ggml_view_4d ( ctx , xbc , d_state , n_group , n_seq_tokens , n_seqs , 4402xbc -> nb [ 1 ], xbc -> nb [ 2 ], xbc -> nb [ 3 ], 2 * xbc -> nb [ 3 ]); 4403} else { 4404x = ggml_new_tensor_4d ( ctx , type , head_dim , n_head , n_seq_tokens , n_seqs ); 4405B = ggml_new_tensor_4d ( ctx , type , d_state , n_group , n_seq_tokens , n_seqs ); 4406C = ggml_new_tensor_4d ( ctx , type , d_state , n_group , n_seq_tokens , n_seqs ); 4407} 4408ggml_tensor * ids = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , n_seqs ); 4409ggml_tensor * out = ggml_ssm_scan ( ctx , s , x , dt , A , B , C , ids , K ); 4410return out ; 4411} 4412 4413 4414void initialize_tensors (ggml_context * ctx ) override { 4415std::random_device rd ; 4416std::default_random_engine rng ( rd ()); 4417for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 4418if ( t -> type == GGML_TYPE_I32 ) { 4419if ( ggml_is_view_op ( t -> op )) { continue ; } 4420// ids: permutation of [0..n_seqs) 4421for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 4422std::vector < int32_t > data ( t -> ne [ 0 ]); 4423for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 4424data [ i ] = i ; 4425} 4426std:: shuffle ( data . begin (), data . end (), rng ); 4427ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 4428} 4429} else if ( ggml_is_view_op ( t -> op )) { 4430continue ; 4431} else if ( t -> ne [ 1 ] == n_head && t -> ne [ 2 ] == 1 ) { 4432// A {1 or d_state, n_head}: negative decay (2-D tensor, ne[2]==1 distinguishes from 3-D/4-D tensors) 4433init_tensor_uniform ( t , weak_decay ? -0.02f : -1.0f , weak_decay ? -0.005f : -0.5f ); 4434} else { 4435init_tensor_uniform ( t ); 4436} 4437} 4438} 4439}; 4440 4441struct test_ssm_scan_rollback : public test_case { 4442const ggml_type type ; 4443 4444const int64_t d_state ; 4445const int64_t head_dim ; 4446const int64_t n_head ; 4447const int64_t n_group ; 4448const int64_t n_seq_tokens ; 4449const int64_t n_seqs ; 4450const int64_t K ; 4451 4452std::string vars () override { 4453return VARS_TO_STR8 ( type , d_state , head_dim , n_head , n_group , n_seq_tokens , n_seqs , K ); 4454} 4455 4456std::string op_desc (ggml_tensor * t ) override { 4457GGML_UNUSED ( t ); 4458return "SSM_SCAN_ROLLBACK" ; 4459} 4460 4461bool run_whole_graph () override { 4462return true; 4463} 4464 4465double max_err () override { 4466return 1e-6 ; 4467} 4468 4469double err ( const float * a , const float * b , size_t n ) override { 4470double result = 0.0 ; 4471for (size_t i = 0 ; i < n ; ++ i ) { 4472result = std:: max ( result , (double) fabsf ( a [ i ])); 4473result = std:: max ( result , (double) fabsf ( b [ i ])); 4474} 4475return result ; 4476} 4477 4478test_ssm_scan_rollback (ggml_type type = GGML_TYPE_F32 , 4479int64_t d_state = 32 , 4480int64_t head_dim = 64 , 4481int64_t n_head = 16 , 4482int64_t n_group = 2 , 4483int64_t n_seq_tokens = 8 , 4484int64_t n_seqs = 2 , 4485int64_t K = 3 ) 4486: type ( type ), d_state ( d_state ), head_dim ( head_dim ), n_head ( n_head ), n_group ( n_group ), 4487n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ), K ( K ) {} 4488 4489ggml_tensor * build_graph (ggml_context * ctx ) override { 4490ggml_tensor * s = ggml_new_tensor_4d ( ctx , type , d_state , head_dim , n_head , n_seqs ); 4491ggml_tensor * x = ggml_new_tensor_4d ( ctx , type , head_dim , n_head , n_seq_tokens , n_seqs ); 4492ggml_tensor * dt = ggml_new_tensor_3d ( ctx , type , n_head , n_seq_tokens , n_seqs ); 4493ggml_tensor * A = ggml_new_tensor_2d ( ctx , type , 1 , n_head ); 4494ggml_tensor * B = ggml_new_tensor_4d ( ctx , type , d_state , n_group , n_seq_tokens , n_seqs ); 4495ggml_tensor * C = ggml_new_tensor_4d ( ctx , type , d_state , n_group , n_seq_tokens , n_seqs ); 4496ggml_tensor * ids = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , n_seqs ); 4497 4498ggml_tensor * full = ggml_ssm_scan ( ctx , s , x , dt , A , B , C , ids , K ); 4499 4500const int64_t y_elems = head_dim * n_head * n_seq_tokens * n_seqs ; 4501const int64_t state_elems = d_state * head_dim * n_head * n_seqs ; 4502 4503ggml_tensor * out = nullptr ; 4504for (int64_t slot = 0 ; slot < K ; ++ slot ) { 4505const int64_t prefix_tokens = n_seq_tokens - slot ; 4506 4507ggml_tensor * x_prefix = ggml_cont ( ctx , ggml_view_4d ( ctx , x , head_dim , n_head , prefix_tokens , n_seqs , x -> nb [ 1 ], x -> nb [ 2 ], x -> nb [ 3 ], 0 )); 4508ggml_tensor * dt_prefix = ggml_cont ( ctx , ggml_view_3d ( ctx , dt , n_head , prefix_tokens , n_seqs , dt -> nb [ 1 ], dt -> nb [ 2 ], 0 )); 4509ggml_tensor * B_prefix = ggml_cont ( ctx , ggml_view_4d ( ctx , B , d_state , n_group , prefix_tokens , n_seqs , B -> nb [ 1 ], B -> nb [ 2 ], B -> nb [ 3 ], 0 )); 4510ggml_tensor * C_prefix = ggml_cont ( ctx , ggml_view_4d ( ctx , C , d_state , n_group , prefix_tokens , n_seqs , C -> nb [ 1 ], C -> nb [ 2 ], C -> nb [ 3 ], 0 )); 4511 4512ggml_tensor * prefix = ggml_ssm_scan ( ctx , s , x_prefix , dt_prefix , A , B_prefix , C_prefix , ids , /*K=*/ 1 ); 4513 4514ggml_tensor * full_state = ggml_view_1d ( ctx , full , state_elems , ( y_elems + slot * state_elems ) * ggml_element_size ( full )); 4515ggml_tensor * prefix_state = ggml_view_1d ( ctx , prefix , state_elems , ( head_dim * n_head * prefix_tokens * n_seqs ) * ggml_element_size ( prefix )); 4516ggml_tensor * diff = ggml_sum ( ctx , ggml_sqr ( ctx , ggml_sub ( ctx , full_state , prefix_state ))); 4517 4518out = out == nullptr ? diff : ggml_add ( ctx , out , diff ); 4519} 4520 4521return out ; 4522} 4523 4524void initialize_tensors (ggml_context * ctx ) override { 4525std::random_device rd ; 4526std::default_random_engine rng ( rd ()); 4527for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 4528if ( t -> type == GGML_TYPE_I32 ) { 4529if ( ggml_is_view_op ( t -> op )) { continue ; } 4530for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 4531std::vector < int32_t > data ( t -> ne [ 0 ]); 4532for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 4533data [ i ] = i ; 4534} 4535std:: shuffle ( data . begin (), data . end (), rng ); 4536ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 4537} 4538} else if ( ggml_is_view_op ( t -> op )) { 4539continue ; 4540} else if ( t -> ne [ 1 ] == n_head && t -> ne [ 2 ] == 1 ) { 4541init_tensor_uniform ( t , -1.0f , -0.5f ); 4542} else { 4543init_tensor_uniform ( t ); 4544} 4545} 4546} 4547}; 4548 4549// GGML_OP_RWKV_WKV6 4550struct test_rwkv_wkv6 : public test_case { 4551const ggml_type type ; 4552 4553const int64_t head_count ; 4554const int64_t head_size ; 4555const int64_t n_seq_tokens ; 4556const int64_t n_seqs ; 4557 4558std::string vars () override { 4559return VARS_TO_STR5 ( type , head_count , head_size , n_seq_tokens , n_seqs ); 4560} 4561 4562test_rwkv_wkv6 (ggml_type type = GGML_TYPE_F32 , 4563int64_t head_count = 32 , int64_t head_size = 64 , int64_t n_seq_tokens = 32 , int64_t n_seqs = 32 ) 4564: type ( type ), head_count ( head_count ), head_size ( head_size ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ) {} 4565 4566ggml_tensor * build_graph (ggml_context * ctx ) override { 4567const int64_t n_tokens = n_seq_tokens * n_seqs ; 4568ggml_tensor * r = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4569ggml_tensor * k = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4570ggml_tensor * v = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4571ggml_tensor * tf = ggml_new_tensor ( ctx , type , 2 , std::vector < int64_t > { head_size , head_count }. data ()); 4572ggml_tensor * td = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4573ggml_tensor * s = ggml_new_tensor ( ctx , type , 2 , std::vector < int64_t > { head_size * head_size * head_count , n_seqs }. data ()); 4574ggml_tensor * out = ggml_rwkv_wkv6 ( ctx , k , v , r , tf , td , s ); 4575return out ; 4576} 4577}; 4578 4579// GGML_OP_GATED_DELTA_NET 4580struct test_gated_delta_net : public test_case { 4581const ggml_type type ; 4582 4583const int64_t head_count ; 4584const int64_t head_size ; 4585const int64_t n_seq_tokens ; 4586const int64_t n_seqs ; 4587const int v_repeat ; 4588const bool permuted ; 4589const bool kda ; 4590const int64_t K ; // snapshot slot count: 1 = final-only, >1 = last K states 4591 4592std::string vars () override { 4593return VARS_TO_STR9 ( type , head_count , head_size , n_seq_tokens , n_seqs , v_repeat , permuted , kda , K ); 4594} 4595 4596test_gated_delta_net (ggml_type type = GGML_TYPE_F32 , 4597int64_t head_count = 4 , int64_t head_size = 16 , int64_t n_seq_tokens = 1 , int64_t n_seqs = 1 , 4598int v_repeat = 1 , bool permuted = false, bool kda = false, int64_t K = 1 ) 4599: type ( type ), head_count ( head_count ), head_size ( head_size ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ), 4600v_repeat ( v_repeat ), permuted ( permuted ), kda ( kda ), K ( K ) {} 4601 4602ggml_tensor * build_graph (ggml_context * ctx ) override { 4603ggml_tensor * q ; 4604ggml_tensor * k ; 4605ggml_tensor * v ; 4606if ( permuted ) { 4607// create with dims 1 and 2 swapped, then permute back to get non-contiguous layout 4608q = ggml_permute ( ctx , ggml_new_tensor_4d ( ctx , type , head_size , n_seq_tokens , head_count , n_seqs ), 0 , 2 , 1 , 3 ); 4609k = ggml_permute ( ctx , ggml_new_tensor_4d ( ctx , type , head_size , n_seq_tokens , head_count , n_seqs ), 0 , 2 , 1 , 3 ); 4610v = ggml_permute ( ctx , ggml_new_tensor_4d ( ctx , type , head_size , n_seq_tokens , head_count * v_repeat , n_seqs ), 0 , 2 , 1 , 3 ); 4611} else { 4612q = ggml_new_tensor_4d ( ctx , type , head_size , head_count , n_seq_tokens , n_seqs ); 4613k = ggml_new_tensor_4d ( ctx , type , head_size , head_count , n_seq_tokens , n_seqs ); 4614v = ggml_new_tensor_4d ( ctx , type , head_size , head_count * v_repeat , n_seq_tokens , n_seqs ); 4615} 4616ggml_set_name ( q , "q" ); 4617ggml_set_name ( k , "k" ); 4618ggml_set_name ( v , "v" ); 4619const int64_t g_ne0 = kda ? head_size : 1 ; 4620ggml_tensor * g = ggml_new_tensor_4d ( ctx , type , g_ne0 , head_count * v_repeat , n_seq_tokens , n_seqs ); 4621ggml_tensor * beta = ggml_new_tensor_4d ( ctx , type , 1 , head_count * v_repeat , n_seq_tokens , n_seqs ); 4622ggml_tensor * state = ggml_new_tensor_4d ( ctx , type , head_size , head_size , head_count * v_repeat , n_seqs ); 4623ggml_set_name ( g , "g" ); 4624ggml_set_name ( beta , "beta" ); 4625ggml_set_name ( state , "state" ); 4626// q/k are L2-normalised in qwen35/kimi-linear before delta_net 4627q = ggml_l2_norm ( ctx , q , 1e-6f ); 4628k = ggml_l2_norm ( ctx , k , 1e-6f ); 4629ggml_tensor * out = ggml_gated_delta_net ( ctx , q , k , v , g , beta , state , K ); 4630return out ; 4631} 4632 4633void initialize_tensors (ggml_context * ctx ) override { 4634for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 4635if ( ggml_is_view_op ( t -> op )) { continue ; } 4636if ( strcmp ( t -> name , "g" ) == 0 ) { 4637init_tensor_uniform ( t , -20.0f , -1e-4f ); 4638} else if ( strcmp ( t -> name , "beta" ) == 0 ) { 4639init_tensor_uniform ( t , 0.0f , 1.0f ); 4640} else if ( strcmp ( t -> name , "v" ) == 0 ) { 4641init_tensor_uniform ( t , -0.3f , 5.0f ); 4642} else { 4643init_tensor_uniform ( t ); 4644} 4645} 4646} 4647}; 4648 4649// GGML_OP_GATED_DELTA_NET + GGML_OP_CPY (recurrent cache fusion) 4650struct test_gated_delta_net_cache_fusion : public test_case { 4651const ggml_type type ; 4652 4653const int64_t head_count ; 4654const int64_t head_size ; 4655const int64_t n_seq_tokens ; 4656const int64_t n_seqs ; 4657const int64_t K ; // snapshot slot count (>1) 4658 4659ggml_tensor * cpy_node = nullptr ; 4660 4661std::string vars () override { 4662return VARS_TO_STR6 ( type , head_count , head_size , n_seq_tokens , n_seqs , K ); 4663} 4664 4665test_gated_delta_net_cache_fusion (ggml_type type = GGML_TYPE_F32 , 4666int64_t head_count = 4 , int64_t head_size = 32 , int64_t n_seq_tokens = 2 , int64_t n_seqs = 1 , 4667int64_t K = 2 ) 4668: type ( type ), head_count ( head_count ), head_size ( head_size ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ), K ( K ) {} 4669 4670ggml_tensor * build_graph (ggml_context * ctx ) override { 4671const int64_t S_v = head_size ; 4672const int64_t H_v = head_count ; 4673const int64_t H_k = head_count ; 4674const int64_t D = S_v * S_v * H_v ; 4675const int64_t n_written = std:: min < int64_t > ( n_seq_tokens , K ); 4676 4677ggml_tensor * q = ggml_new_tensor_4d ( ctx , type , head_size , H_k , n_seq_tokens , n_seqs ); 4678ggml_tensor * k = ggml_new_tensor_4d ( ctx , type , head_size , H_k , n_seq_tokens , n_seqs ); 4679ggml_tensor * v = ggml_new_tensor_4d ( ctx , type , head_size , H_v , n_seq_tokens , n_seqs ); 4680ggml_set_name ( q , "q" ); 4681ggml_set_name ( k , "k" ); 4682ggml_set_name ( v , "v" ); 4683ggml_tensor * g = ggml_new_tensor_4d ( ctx , type , 1 , H_v , n_seq_tokens , n_seqs ); 4684ggml_tensor * beta = ggml_new_tensor_4d ( ctx , type , 1 , H_v , n_seq_tokens , n_seqs ); 4685ggml_tensor * state = ggml_new_tensor_4d ( ctx , type , head_size , head_size , H_v , n_seqs ); 4686ggml_set_name ( g , "g" ); 4687ggml_set_name ( beta , "beta" ); 4688ggml_set_name ( state , "state" ); 4689 4690q = ggml_l2_norm ( ctx , q , 1e-6f ); 4691k = ggml_l2_norm ( ctx , k , 1e-6f ); 4692 4693ggml_tensor * gdn_out = ggml_gated_delta_net ( ctx , q , k , v , g , beta , state , K ); 4694ggml_set_name ( gdn_out , "gdn_out" ); 4695 4696// attn scores view (first part of the gdn output) 4697ggml_tensor * attn = ggml_view_4d ( ctx , gdn_out , 4698S_v , H_v , n_seq_tokens , n_seqs , 4699ggml_row_size ( gdn_out -> type , S_v ), 4700ggml_row_size ( gdn_out -> type , S_v * H_v ), 4701ggml_row_size ( gdn_out -> type , S_v * H_v * n_seq_tokens ), 0 ); 4702ggml_set_name ( attn , "attn" ); 4703 4704// snapshot tail view [D, n_seqs, n_written] 4705const int64_t attn_score_elems = S_v * H_v * n_seq_tokens * n_seqs ; 4706ggml_tensor * src = ggml_view_3d ( ctx , gdn_out , 4707D , n_seqs , n_written , 4708ggml_row_size ( gdn_out -> type , D ), 4709ggml_row_size ( gdn_out -> type , D * n_seqs ), 4710ggml_row_size ( gdn_out -> type , attn_score_elems )); 4711 4712// recurrent cache view [D, n_seqs, n_written] 4713ggml_tensor * cache = ggml_new_tensor_3d ( ctx , type , D , n_seqs , n_written ); 4714ggml_set_name ( cache , "cache" ); 4715ggml_tensor * dst = ggml_view_3d ( ctx , cache , 4716D , n_seqs , n_written , 4717ggml_row_size ( cache -> type , D ), 4718ggml_row_size ( cache -> type , D * n_seqs ), 0 ); 4719 4720ggml_tensor * cpy = ggml_cpy ( ctx , src , dst ); 4721ggml_set_name ( cpy , "gdn_cache_cpy" ); 4722cpy_node = cpy ; 4723 4724// read the cpy output (not the plain dst view, which would not pull the cpy into the graph) 4725// so that neither the gdn nor the cpy is the graph output 4726ggml_tensor * out = ggml_sum ( ctx , cpy ); 4727return out ; 4728} 4729 4730std::string op_desc (ggml_tensor * t ) override { 4731GGML_UNUSED ( t ); 4732return "GATED_DELTA_NET_CACHE_FUSION" ; 4733} 4734 4735bool run_whole_graph () override { return true; } 4736std::vector < ggml_tensor *> fusion_test_nodes () override { return { cpy_node }; } 4737 4738uint64_t op_flops (ggml_tensor * t ) override { 4739GGML_UNUSED ( t ); 4740const uint64_t S_v = head_size ; 4741const uint64_t H_v = head_count ; 4742const uint64_t T = n_seq_tokens ; 4743const uint64_t B = n_seqs ; 4744return ( 4ull * S_v + 2ull * S_v * S_v ) * H_v * T * B ; 4745} 4746 4747void initialize_tensors (ggml_context * ctx ) override { 4748for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 4749if ( ggml_is_view_op ( t -> op )) { continue ; } 4750if ( strcmp ( t -> name , "g" ) == 0 ) { 4751init_tensor_uniform ( t , -20.0f , -1e-4f ); 4752} else if ( strcmp ( t -> name , "beta" ) == 0 ) { 4753init_tensor_uniform ( t , 0.0f , 1.0f ); 4754} else if ( strcmp ( t -> name , "v" ) == 0 ) { 4755init_tensor_uniform ( t , -0.3f , 5.0f ); 4756} else if ( strcmp ( t -> name , "cache" ) == 0 ) { 4757init_tensor_uniform ( t , 0.0f , 0.0f ); 4758} else { 4759init_tensor_uniform ( t ); 4760} 4761} 4762} 4763}; 4764 4765// GGML_OP_GATED_LINEAR_ATTN 4766struct test_gla : public test_case { 4767const ggml_type type ; 4768 4769const int64_t head_count ; 4770const int64_t head_size ; 4771const int64_t n_seq_tokens ; 4772const int64_t n_seqs ; 4773 4774std::string vars () override { 4775return VARS_TO_STR5 ( type , head_count , head_size , n_seq_tokens , n_seqs ); 4776} 4777 4778test_gla (ggml_type type = GGML_TYPE_F32 , 4779int64_t head_count = 32 , int64_t head_size = 64 , int64_t n_seq_tokens = 32 , int64_t n_seqs = 32 ) 4780: type ( type ), head_count ( head_count ), head_size ( head_size ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ) {} 4781 4782ggml_tensor * build_graph (ggml_context * ctx ) override { 4783const int64_t n_tokens = n_seq_tokens * n_seqs ; 4784ggml_tensor * q = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4785ggml_tensor * k = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4786ggml_tensor * v = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4787ggml_tensor * g = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4788ggml_tensor * s = ggml_new_tensor ( ctx , type , 2 , std::vector < int64_t > { head_size * head_size * head_count , n_seqs }. data ()); 4789ggml_tensor * out = ggml_gated_linear_attn ( ctx , k , v , q , g , s , pow ( head_size , -0.5 )); 4790return out ; 4791} 4792}; 4793 4794// GGML_OP_RWKV_WKV7 4795struct test_rwkv_wkv7 : public test_case { 4796const ggml_type type ; 4797 4798const int64_t head_count ; 4799const int64_t head_size ; 4800const int64_t n_seq_tokens ; 4801const int64_t n_seqs ; 4802 4803std::string vars () override { 4804return VARS_TO_STR5 ( type , head_count , head_size , n_seq_tokens , n_seqs ); 4805} 4806 4807test_rwkv_wkv7 (ggml_type type = GGML_TYPE_F32 , 4808int64_t head_count = 32 , int64_t head_size = 64 , int64_t n_seq_tokens = 32 , int64_t n_seqs = 32 ) 4809: type ( type ), head_count ( head_count ), head_size ( head_size ), n_seq_tokens ( n_seq_tokens ), n_seqs ( n_seqs ) {} 4810 4811ggml_tensor * build_graph (ggml_context * ctx ) override { 4812const int64_t n_tokens = n_seq_tokens * n_seqs ; 4813ggml_tensor * r = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4814ggml_tensor * w = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4815ggml_tensor * k = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4816ggml_tensor * v = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4817ggml_tensor * a = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4818ggml_tensor * b = ggml_new_tensor ( ctx , type , 3 , std::vector < int64_t > { head_size , head_count , n_tokens }. data ()); 4819// Outputs may become NaN with long seqlen without these normalization 4820a = ggml_l2_norm ( ctx , a , 1e-7F ); 4821b = ggml_l2_norm ( ctx , b , 1e-7F ); 4822ggml_tensor * s = ggml_new_tensor ( ctx , type , 2 , std::vector < int64_t > { head_size * head_size * head_count , n_seqs }. data ()); 4823ggml_tensor * out = ggml_rwkv_wkv7 ( ctx , r , w , k , v , a , b , s ); 4824return out ; 4825} 4826}; 4827 4828// GGML_OP_MUL_MAT 4829struct test_mul_mat : public test_case { 4830const ggml_type type_a ; 4831const ggml_type type_b ; 4832const int64_t m ; 4833const int64_t n ; 4834const int64_t k ; 4835const std::array < int64_t, 2 > bs ; // dims 3 and 4 4836const std::array < int64_t, 2 > nr ; // repeat in dims 3 and 4 4837const std::array < int64_t, 4 > per ; // permutation of dimensions 4838const int64_t k_v ; // size of k in memory, resulting in a non-contiguous view for k_v > k, no view for k_v == 0 4839const uint32_t o ; // number of outputs 4840const bool src_overlap ; // a and b are overlapping views of the same tensor 4841 4842std::string vars () override { 4843return VARS_TO_STR11 ( type_a , type_b , m , n , k , bs , nr , per , k_v , o , src_overlap ); 4844} 4845 4846double max_nmse_err () override { 4847return 5e-4 ; 4848} 4849 4850double max_nmse_err (ggml_backend_t backend ) override { 4851// for blackwell we quantize activations to mxfp4 instead of q8_1 so we add higher tolerance 4852if (( type_a == GGML_TYPE_MXFP4 || type_a == GGML_TYPE_NVFP4 ) && backend_has_feature ( backend , "BLACKWELL_NATIVE_FP4" )) { 4853return 2e-2 ; 4854} 4855return max_nmse_err (); 4856} 4857 4858int64_t grad_nmax () override { 4859return 20000 ; 4860} 4861 4862uint64_t op_flops (ggml_tensor * t ) override { 4863GGML_UNUSED ( t ); 4864return 2 * m * n * k * bs [ 0 ] * nr [ 0 ] * bs [ 1 ] * nr [ 1 ]; 4865} 4866 4867test_mul_mat (ggml_type type_a = GGML_TYPE_F32 , ggml_type type_b = GGML_TYPE_F32 , 4868int64_t m = 32 , int64_t n = 32 , int64_t k = 32 , 4869std::array < int64_t, 2 > bs = { 10 , 10 }, 4870std::array < int64_t, 2 > nr = { 2 , 2 }, 4871std::array < int64_t, 4 > per = { 0 , 1 , 2 , 3 }, 4872int64_t k_v = 0 , uint32_t o = 1 , bool src_overlap = false) 4873: type_a ( type_a ), type_b ( type_b ), m ( m ), n ( n ), k ( k ), bs ( bs ), nr ( nr ), per ( per ), k_v ( k_v ), o ( o ), src_overlap ( src_overlap ) {} 4874 4875ggml_tensor * build_graph (ggml_context * ctx ) override { 4876// C^T = A * B^T: (k, m) * (k, n) => (m, n) 4877ggml_tensor * a ; 4878ggml_tensor * b ; 4879 4880const int npermuted = ( per [ 0 ] != 0 ) + ( per [ 1 ] != 1 ) + ( per [ 2 ] != 2 ) + ( per [ 3 ] != 3 ); 4881if ( npermuted > 0 ) { 4882GGML_ASSERT ( npermuted == 2 ); 4883GGML_ASSERT ( k_v == 0 ); // not handled 4884GGML_ASSERT (! ggml_is_quantized ( type_a ) || per [ 0 ] == 0 ); 4885GGML_ASSERT (! ggml_is_quantized ( type_b ) || per [ 0 ] == 0 ); 4886 4887// Create tensors with the permuted dimensions, then permute them back to the dimensions given by m,n,k. 4888const int64_t ne_a [ 4 ] = { k , m , bs [ 0 ], bs [ 1 ]}; 4889const int64_t ne_b [ 4 ] = { k , n , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ]}; 4890 4891a = ggml_new_tensor_4d ( ctx , type_a , ne_a [ per [ 0 ]], ne_a [ per [ 1 ]], ne_a [ per [ 2 ]], ne_a [ per [ 3 ]]); 4892b = ggml_new_tensor_4d ( ctx , type_b , ne_b [ per [ 0 ]], ne_b [ per [ 1 ]], ne_b [ per [ 2 ]], ne_b [ per [ 3 ]]); 4893if (! ggml_is_quantized ( type_a )) { 4894if ( bs [ 1 ] == 1 && nr [ 1 ] == 1 ) { 4895ggml_set_param ( a ); 4896} 4897ggml_set_param ( b ); 4898} 4899ggml_set_name ( a , "a" ); 4900ggml_set_name ( b , "b" ); 4901 4902a = ggml_permute ( ctx , a , per [ 0 ], per [ 1 ], per [ 2 ], per [ 3 ]); 4903b = ggml_permute ( ctx , b , per [ 0 ], per [ 1 ], per [ 2 ], per [ 3 ]); 4904ggml_set_name ( a , "a_permuted" ); 4905ggml_set_name ( b , "b_permuted" ); 4906} else if ( src_overlap ) { 4907GGML_ASSERT ( type_a == type_b ); 4908GGML_ASSERT ( k_v == 0 ); 4909 4910// a and b are interleaved views of the same tensor: (e.g. fused QKV in MiniMax-01) 4911ggml_tensor * base = ggml_new_tensor_4d ( ctx , type_a , 2 * k , std:: max ( m , n ), bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ]); 4912ggml_set_name ( base , "base" ); 4913 4914a = ggml_view_4d ( ctx , base , k , m , bs [ 0 ], bs [ 1 ], base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], 0 ); 4915b = ggml_view_4d ( ctx , base , k , n , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ], base -> nb [ 1 ], base -> nb [ 2 ], base -> nb [ 3 ], k * ggml_type_size ( type_a )); 4916ggml_set_name ( a , "a" ); 4917ggml_set_name ( b , "b" ); 4918} else { 4919const int64_t k_physical = k_v == 0 ? k : k_v ; 4920a = ggml_new_tensor_4d ( ctx , type_a , k_physical , m , bs [ 0 ], bs [ 1 ]); 4921b = ggml_new_tensor_4d ( ctx , type_b , k_physical , n , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ]); 4922 4923if (! ggml_is_quantized ( type_a )) { 4924if ( bs [ 1 ] == 1 && nr [ 1 ] == 1 ) { 4925ggml_set_param ( a ); 4926} 4927ggml_set_param ( b ); 4928} 4929 4930if ( k_v != 0 ) { 4931GGML_ASSERT ( k_v > k ); 4932a = ggml_view_4d ( ctx , a , k , m , bs [ 0 ], bs [ 1 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 4933b = ggml_view_4d ( ctx , b , k , n , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 4934} 4935ggml_set_name ( a , "a" ); 4936ggml_set_name ( b , "b" ); 4937} 4938 4939ggml_tensor * out = ggml_mul_mat ( ctx , a , b ); 4940ggml_set_name ( out , "out" ); 4941for (uint32_t i = 1 ; i < o ; ++ i ) { 4942ggml_tensor * out2 = ggml_mul_mat ( ctx , a , b ); 4943ggml_set_name ( out2 , "out2" ); 4944out = ggml_add ( ctx , out , out2 ); 4945} 4946 4947return out ; 4948} 4949 4950bool run_whole_graph () override { return o > 1 ; } 4951 4952std::string op_desc (ggml_tensor * t ) override { 4953GGML_UNUSED ( t ); 4954return ggml_op_name ( GGML_OP_MUL_MAT ); 4955} 4956}; 4957 4958// GGML_HINT_SRC0_IS_HADAMARD 4959struct test_mul_mat_hadamard : public test_mul_mat { 4960test_mul_mat_hadamard (ggml_type type_a = GGML_TYPE_F32 , ggml_type type_b = GGML_TYPE_F32 , 4961int64_t m = 32 , int64_t n = 32 , int64_t k = 32 , 4962std::array < int64_t, 2 > bs = { 1 , 1 }, 4963std::array < int64_t, 2 > nr = { 1 , 1 }) 4964: test_mul_mat ( type_a , type_b , m , n , k , bs , nr ) { 4965GGML_ASSERT ( type_a == GGML_TYPE_F32 ); 4966} 4967 4968ggml_tensor * build_graph (ggml_context * ctx ) override { 4969ggml_tensor * out = test_mul_mat:: build_graph ( ctx ); 4970// Find the mul_mat op in the graph and set the hint 4971for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 4972if ( t -> op == GGML_OP_MUL_MAT ) { 4973ggml_mul_mat_set_hint ( t , GGML_HINT_SRC0_IS_HADAMARD ); 4974} 4975} 4976return out ; 4977} 4978 4979void initialize_tensors (ggml_context * ctx ) override { 4980for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 4981if ( strcmp ( t -> name , "a" ) == 0 ) { 4982const int64_t n_cols = t -> ne [ 0 ]; 4983const int64_t n_rows = ggml_nrows ( t ); 4984std::vector < float > data (n_cols * n_rows ); 4985float scale = 1.0f / sqrtf ((float) n_cols ); 4986for (int64_t r = 0 ; r < n_rows ; r ++ ) { 4987float * row_data = data . data () + r * n_cols ; 4988for (int64_t i = 0 ; i < n_cols ; i ++ ) { 4989int pop = 0 ; 4990int64_t val = r & i ; 4991while ( val ) { 4992pop += ( val & 1 ); 4993val >>= 1 ; 4994} 4995row_data [ i ] = ( pop % 2 == 0 ) ? scale : - scale ; 4996} 4997} 4998ggml_backend_tensor_set ( t , data . data (), 0 , data . size () * sizeof (float)); 4999} else if ( t -> type == GGML_TYPE_F32 || t -> type == GGML_TYPE_F16 ) { 5000init_tensor_uniform ( t ); 5001} 5002} 5003} 5004 5005std::string op_desc (ggml_tensor * t ) override { 5006GGML_UNUSED ( t ); 5007return "MUL_MAT_HADAMARD" ; 5008} 5009}; 5010 5011static void init_mul_mat_id_ids (ggml_context * ctx , int n_mats ) { 5012std::random_device rd ; 5013std::default_random_engine rng ( rd ()); 5014for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5015if ( t -> type != GGML_TYPE_I32 || ggml_is_view_op ( t -> op )) { 5016continue ; 5017} 5018for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 5019std::vector < int32_t > data ( t -> ne [ 0 ]); 5020for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 5021data [ i ] = i % n_mats ; 5022} 5023std:: shuffle ( data . begin (), data . end (), rng ); 5024ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 5025} 5026} 5027} 5028 5029static void init_mul_mat_id_tensors (ggml_context * ctx , int n_mats ) { 5030for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5031if ( t -> type != GGML_TYPE_I32 ) { 5032init_tensor_uniform ( t ); 5033} 5034} 5035init_mul_mat_id_ids ( ctx , n_mats ); 5036} 5037 5038// GGML_OP_MUL_MAT_ID 5039struct test_mul_mat_id : public test_case { 5040const ggml_type type_a ; 5041const ggml_type type_b ; 5042const int n_mats ; 5043const int n_used ; 5044const bool b ; // broadcast b matrix 5045const int64_t m ; 5046const int64_t n ; 5047const int64_t k ; 5048 5049std::string vars () override { 5050return VARS_TO_STR8 ( type_a , type_b , n_mats , n_used , b , m , n , k ); 5051} 5052 5053double max_nmse_err () override { 5054return 5e-4 ; 5055} 5056 5057double max_nmse_err (ggml_backend_t backend ) override { 5058// for blackwell we quantize activations to mxfp4 instead of q8_1 so we add higher tolerance 5059if (( type_a == GGML_TYPE_MXFP4 || type_a == GGML_TYPE_NVFP4 ) && backend_has_feature ( backend , "BLACKWELL_NATIVE_FP4" )) { 5060return 2e-2 ; 5061} 5062return max_nmse_err (); 5063} 5064 5065uint64_t op_flops (ggml_tensor * t ) override { 5066GGML_UNUSED ( t ); 5067return 2 * m * k * n * n_used ; 5068} 5069 5070test_mul_mat_id (ggml_type type_a = GGML_TYPE_F32 , ggml_type type_b = GGML_TYPE_F32 , 5071int n_mats = 8 , int n_used = 2 , bool b = false, 5072int64_t m = 32 , int64_t n = 32 , int64_t k = 32 ) 5073: type_a ( type_a ), type_b ( type_b ), n_mats ( n_mats ), n_used ( n_used ), b ( b ), 5074m ( m ), n ( n ), k ( k ) { 5075GGML_ASSERT ( n_used <= n_mats ); 5076} 5077 5078ggml_tensor * build_graph (ggml_context * ctx ) override { 5079// C^T = A * B^T: (k, m) * (k, n) => (m, n) 5080ggml_tensor * as = ggml_new_tensor_3d ( ctx , type_a , k , m , n_mats ); 5081ggml_set_name ( as , "as" ); 5082 5083ggml_tensor * ids = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , n_mats , n ); 5084ggml_set_name ( ids , "ids" ); 5085if ( n_used != n_mats ) { 5086ids = ggml_view_2d ( ctx , ids , n_used , n , ids -> nb [ 1 ], 0 ); 5087ggml_set_name ( ids , "view_of_ids" ); 5088} 5089 5090ggml_tensor * b = ggml_new_tensor_3d ( ctx , type_b , k , this -> b ? 1 : n_used , n ); 5091ggml_set_name ( b , "b" ); 5092 5093ggml_tensor * out = ggml_mul_mat_id ( ctx , as , b , ids ); 5094ggml_set_name ( out , "out" ); 5095 5096return out ; 5097} 5098 5099void initialize_tensors (ggml_context * ctx ) override { 5100init_mul_mat_id_tensors ( ctx , n_mats ); 5101} 5102 5103void reinit_perf_iter (ggml_context * ctx ) override { 5104init_mul_mat_id_ids ( ctx , n_mats ); 5105} 5106}; 5107 5108// GGML_OP_MUL_MAT_ID + GGML_OP_ADD or GGML_OP_MUL 5109struct test_mul_mat_id_fusion : public test_case { 5110const ggml_type type_a ; 5111const ggml_type type_b ; 5112const int n_mats ; 5113const int n_used ; 5114const bool b ; // broadcast b matrix 5115const int64_t m ; 5116const int64_t n ; 5117const int64_t k ; 5118const uint32_t o ; // number of outputs 5119const bool mul ; 5120 5121std::string vars () override { 5122return VARS_TO_STR10 ( type_a , type_b , n_mats , n_used , b , m , n , k , o , mul ); 5123} 5124 5125double max_nmse_err () override { 5126return 5e-4 ; 5127} 5128 5129uint64_t op_flops (ggml_tensor * t ) override { 5130GGML_UNUSED ( t ); 5131return 2 * m * k * n * n_used ; 5132} 5133 5134test_mul_mat_id_fusion (ggml_type type_a = GGML_TYPE_F32 , ggml_type type_b = GGML_TYPE_F32 , 5135int n_mats = 8 , int n_used = 2 , bool b = false, 5136int64_t m = 32 , int64_t n = 32 , int64_t k = 32 , uint32_t o = 1 , bool mul = false) 5137: type_a ( type_a ), type_b ( type_b ), n_mats ( n_mats ), n_used ( n_used ), b ( b ), 5138m ( m ), n ( n ), k ( k ), o ( o ), mul ( mul ) { 5139GGML_ASSERT ( n_used <= n_mats ); 5140} 5141 5142ggml_tensor * build_graph (ggml_context * ctx ) override { 5143// C^T = A * B^T: (k, m) * (k, n) => (m, n) 5144ggml_tensor * as = ggml_new_tensor_3d ( ctx , type_a , k , m , n_mats ); 5145ggml_set_name ( as , "as" ); 5146 5147ggml_tensor * ids = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , n_mats , n ); 5148ggml_set_name ( ids , "ids" ); 5149if ( n_used != n_mats ) { 5150ids = ggml_view_2d ( ctx , ids , n_used , n , ids -> nb [ 1 ], 0 ); 5151ggml_set_name ( ids , "view_of_ids" ); 5152} 5153 5154ggml_tensor * b = ggml_new_tensor_3d ( ctx , type_b , k , this -> b ? 1 : n_used , n ); 5155ggml_set_name ( b , "b" ); 5156 5157ggml_tensor * out = ggml_mul_mat_id ( ctx , as , b , ids ); 5158ggml_set_name ( out , "out" ); 5159 5160for (uint32_t i = 1 ; i < o ; ++ i ) { 5161ggml_tensor * a2 = ggml_new_tensor_3d ( ctx , type_a , k , m , n_mats ); 5162ggml_tensor * out2 = ggml_mul_mat_id ( ctx , a2 , b , ids ); 5163ggml_set_name ( out2 , "out2" ); 5164out = ggml_add ( ctx , out , out2 ); 5165} 5166 5167if ( mul ) { 5168std::array < int64_t, 4 > ne { 1 , out -> ne [ 1 ], out -> ne [ 2 ], out -> ne [ 3 ] }; 5169ne [ 0 ] = 1 ; 5170ggml_tensor * m = ggml_new_tensor ( ctx , out -> type , 4 , ne . data ()); 5171out = ggml_mul ( ctx , out , m ); 5172} 5173 5174return out ; 5175} 5176 5177void initialize_tensors (ggml_context * ctx ) override { 5178init_mul_mat_id_tensors ( ctx , n_mats ); 5179} 5180 5181bool run_whole_graph () override { return true; } 5182 5183std::string op_desc (ggml_tensor * t ) override { 5184GGML_UNUSED ( t ); 5185return "MUL_MAT_ID_FUSION" ; 5186} 5187}; 5188 5189// GGML_OP_OUT_PROD 5190struct test_out_prod : public test_case { 5191const ggml_type type_a ; 5192const ggml_type type_b ; 5193const int64_t m ; 5194const int64_t n ; 5195const int64_t k ; 5196const std::array < int64_t, 2 > bs ; // dims 3 and 4 5197const std::array < int64_t, 2 > nr ; // repeat in dims 3 and 4 5198const bool trans_b ; 5199 5200std::string vars () override { 5201return VARS_TO_STR8 ( type_a , type_b , m , n , k , bs , nr , trans_b ); 5202} 5203 5204double max_nmse_err () override { 5205return 5e-4 ; 5206} 5207 5208test_out_prod (ggml_type type_a = GGML_TYPE_F32 , ggml_type type_b = GGML_TYPE_F32 , 5209int64_t m = 32 , int64_t n = 32 , int64_t k = 32 , 5210std::array < int64_t, 2 > bs = { 10 , 10 }, 5211std::array < int64_t, 2 > nr = { 2 , 2 }, 5212bool trans_b = false) 5213: type_a ( type_a ), type_b ( type_b ), m ( m ), n ( n ), k ( k ), bs ( bs ), nr ( nr ), trans_b ( trans_b ) {} 5214 5215ggml_tensor * build_graph (ggml_context * ctx ) override { 5216ggml_tensor * a = ggml_new_tensor_4d ( ctx , type_a , m , k , bs [ 0 ], bs [ 1 ]); 5217ggml_set_name ( a , "a" ); 5218 5219ggml_tensor * b ; 5220if ( trans_b ) { 5221b = ggml_new_tensor_4d ( ctx , type_b , k , n , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ]); 5222b = ggml_transpose ( ctx , b ); 5223} else { 5224b = ggml_new_tensor_4d ( ctx , type_b , n , k , bs [ 0 ] * nr [ 0 ], bs [ 1 ] * nr [ 1 ]); 5225} 5226ggml_set_name ( b , "b" ); 5227 5228ggml_tensor * out = ggml_out_prod ( ctx , a , b ); 5229ggml_set_name ( out , "out" ); 5230 5231return out ; 5232} 5233}; 5234 5235// GGML_OP_SQR 5236struct test_sqr : public test_case { 5237const ggml_type type ; 5238const std::array < int64_t, 4 > ne ; 5239 5240std::string vars () override { 5241return VARS_TO_STR2 ( type , ne ); 5242} 5243 5244test_sqr (ggml_type type = GGML_TYPE_F32 , 5245std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 5246: type ( type ), ne ( ne ) {} 5247 5248ggml_tensor * build_graph (ggml_context * ctx ) override { 5249ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5250ggml_set_param ( a ); 5251ggml_set_name ( a , "a" ); 5252 5253ggml_tensor * out = ggml_sqr ( ctx , a ); 5254ggml_set_name ( out , "out" ); 5255 5256return out ; 5257} 5258 5259float grad_eps () override { 5260return 0.1f * 0.25f * ne [ 0 ] * ne [ 1 ] * ne [ 2 ] * ne [ 3 ]; // 10% of expected value of sum. 5261} 5262}; 5263 5264// GGML_OP_SQRT 5265struct test_sqrt : public test_case { 5266const ggml_type type ; 5267const std::array < int64_t, 4 > ne ; 5268 5269std::string vars () override { 5270return VARS_TO_STR2 ( type , ne ); 5271} 5272 5273test_sqrt (ggml_type type = GGML_TYPE_F32 , 5274std::array < int64_t, 4 > ne = { 10 , 3 , 3 , 2 }) 5275: type ( type ), ne ( ne ) {} 5276 5277ggml_tensor * build_graph (ggml_context * ctx ) override { 5278ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5279ggml_set_param ( a ); 5280ggml_set_name ( a , "a" ); 5281 5282ggml_tensor * out = ggml_sqrt ( ctx , a ); 5283ggml_set_name ( out , "out" ); 5284 5285return out ; 5286} 5287 5288void initialize_tensors (ggml_context * ctx ) override { 5289// fill with positive values 5290for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5291init_tensor_uniform ( t , 50.0f , 100.0f ); 5292} 5293} 5294 5295float grad_eps () override { 5296return 20.0f ; 5297} 5298 5299bool grad_precise () override { 5300return true; 5301} 5302}; 5303 5304// GGML_OP_LOG 5305struct test_log : public test_case { 5306const ggml_type type ; 5307const std::array < int64_t, 4 > ne ; 5308 5309std::string vars () override { 5310return VARS_TO_STR2 ( type , ne ); 5311} 5312 5313test_log (ggml_type type = GGML_TYPE_F32 , 5314std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 5315: type ( type ), ne ( ne ) {} 5316 5317ggml_tensor * build_graph (ggml_context * ctx ) override { 5318ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5319ggml_set_param ( a ); 5320ggml_set_name ( a , "a" ); 5321 5322ggml_tensor * out = ggml_log ( ctx , a ); 5323ggml_set_name ( out , "out" ); 5324 5325return out ; 5326} 5327 5328void initialize_tensors (ggml_context * ctx ) override { 5329for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5330// log(1) == 0, cluster values there to keep the sum low for better precision in the backward pass: 5331init_tensor_uniform ( t , 0.9f , 1.1f ); 5332} 5333} 5334 5335bool grad_precise () override { 5336return true; 5337} 5338}; 5339 5340// GGML_OP_SIN 5341struct test_sin : public test_case { 5342const ggml_type type ; 5343const std::array < int64_t, 4 > ne ; 5344 5345std::string vars () override { 5346return VARS_TO_STR2 ( type , ne ); 5347} 5348 5349test_sin (ggml_type type = GGML_TYPE_F32 , 5350std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5351: type ( type ), ne ( ne ) {} 5352 5353ggml_tensor * build_graph (ggml_context * ctx ) override { 5354ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5355ggml_set_param ( a ); 5356ggml_set_name ( a , "a" ); 5357 5358ggml_tensor * out = ggml_sin ( ctx , a ); 5359ggml_set_name ( out , "out" ); 5360 5361return out ; 5362} 5363 5364void initialize_tensors (ggml_context * ctx ) override { 5365for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5366init_tensor_uniform ( t , -6.5f , 6.5f ); // Covers interval [-2*pi, 2*pi]. 5367} 5368} 5369 5370double max_maa_err () override { 5371return 1e-3 ; 5372} 5373 5374float grad_eps () override { 5375return 0.2f ; 5376} 5377 5378bool grad_precise () override { 5379return true; 5380} 5381}; 5382 5383// GGML_OP_COS 5384struct test_cos : public test_case { 5385const ggml_type type ; 5386const std::array < int64_t, 4 > ne ; 5387 5388std::string vars () override { 5389return VARS_TO_STR2 ( type , ne ); 5390} 5391 5392test_cos (ggml_type type = GGML_TYPE_F32 , 5393std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5394: type ( type ), ne ( ne ) {} 5395 5396ggml_tensor * build_graph (ggml_context * ctx ) override { 5397ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5398ggml_set_param ( a ); 5399ggml_set_name ( a , "a" ); 5400 5401ggml_tensor * out = ggml_cos ( ctx , a ); 5402ggml_set_name ( out , "out" ); 5403 5404return out ; 5405} 5406 5407void initialize_tensors (ggml_context * ctx ) override { 5408for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5409init_tensor_uniform ( t , -6.5f , 6.5f ); // Covers interval [-2*pi, 2*pi]. 5410} 5411} 5412 5413double max_maa_err () override { 5414return 1e-3 ; 5415} 5416 5417float grad_eps () override { 5418return 0.2f ; 5419} 5420 5421bool grad_precise () override { 5422return true; 5423} 5424}; 5425 5426// GGML_OP_CLAMP 5427struct test_clamp : public test_case { 5428const ggml_type type ; 5429const std::array < int64_t, 4 > ne ; 5430float min ; 5431float max ; 5432 5433std::string vars () override { 5434return VARS_TO_STR4 ( type , ne , min , max ); 5435} 5436 5437test_clamp (ggml_type type = GGML_TYPE_F32 , 5438std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 5439float min = -0.5f , float max = 0.5f ) 5440: type ( type ), ne ( ne ), min ( min ), max ( max ) {} 5441 5442ggml_tensor * build_graph (ggml_context * ctx ) override { 5443ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5444ggml_set_name ( a , "a" ); 5445 5446ggml_tensor * out = ggml_clamp ( ctx , a , min , max ); 5447ggml_set_name ( out , "out" ); 5448 5449return out ; 5450} 5451 5452float grad_eps () override { 5453return 1e-2f ; 5454} 5455 5456std::vector < float > grad_expect () override { 5457return { 0.0f , 1.0f }; 5458} 5459}; 5460 5461// GGML_OP_FLOOR 5462struct test_floor : public test_case { 5463const ggml_type type ; 5464const std::array < int64_t, 4 > ne ; 5465 5466std::string vars () override { 5467return VARS_TO_STR2 ( type , ne ); 5468} 5469 5470test_floor (ggml_type type = GGML_TYPE_F32 , 5471std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5472: type ( type ), ne ( ne ) {} 5473 5474ggml_tensor * build_graph (ggml_context * ctx ) override { 5475ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5476ggml_set_param ( a ); 5477ggml_set_name ( a , "a" ); 5478 5479ggml_tensor * out = ggml_floor ( ctx , a ); 5480ggml_set_name ( out , "out" ); 5481 5482return out ; 5483} 5484 5485void initialize_tensors (ggml_context * ctx ) override { 5486for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5487init_tensor_uniform ( t , -10.0f , 10.0f ); 5488} 5489} 5490}; 5491 5492// GGML_OP_CEIL 5493struct test_ceil : public test_case { 5494const ggml_type type ; 5495const std::array < int64_t, 4 > ne ; 5496 5497std::string vars () override { 5498return VARS_TO_STR2 ( type , ne ); 5499} 5500 5501test_ceil (ggml_type type = GGML_TYPE_F32 , 5502std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5503: type ( type ), ne ( ne ) {} 5504 5505ggml_tensor * build_graph (ggml_context * ctx ) override { 5506ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5507ggml_set_param ( a ); 5508ggml_set_name ( a , "a" ); 5509 5510ggml_tensor * out = ggml_ceil ( ctx , a ); 5511ggml_set_name ( out , "out" ); 5512 5513return out ; 5514} 5515 5516void initialize_tensors (ggml_context * ctx ) override { 5517for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5518init_tensor_uniform ( t , -10.0f , 10.0f ); 5519} 5520} 5521}; 5522 5523// GGML_OP_ROUND 5524struct test_round : public test_case { 5525const ggml_type type ; 5526const std::array < int64_t, 4 > ne ; 5527 5528std::string vars () override { 5529return VARS_TO_STR2 ( type , ne ); 5530} 5531 5532test_round (ggml_type type = GGML_TYPE_F32 , 5533std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5534: type ( type ), ne ( ne ) {} 5535 5536ggml_tensor * build_graph (ggml_context * ctx ) override { 5537ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5538ggml_set_param ( a ); 5539ggml_set_name ( a , "a" ); 5540 5541ggml_tensor * out = ggml_round ( ctx , a ); 5542ggml_set_name ( out , "out" ); 5543 5544return out ; 5545} 5546 5547void initialize_tensors (ggml_context * ctx ) override { 5548for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5549init_tensor_uniform ( t , -10.0f , 10.0f ); 5550} 5551} 5552}; 5553 5554// GGML_OP_TRUNC 5555struct test_trunc : public test_case { 5556const ggml_type type ; 5557const std::array < int64_t, 4 > ne ; 5558 5559std::string vars () override { 5560return VARS_TO_STR2 ( type , ne ); 5561} 5562 5563test_trunc (ggml_type type = GGML_TYPE_F32 , 5564std::array < int64_t, 4 > ne = { 10 , 2 , 2 , 2 }) 5565: type ( type ), ne ( ne ) {} 5566 5567ggml_tensor * build_graph (ggml_context * ctx ) override { 5568ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5569ggml_set_param ( a ); 5570ggml_set_name ( a , "a" ); 5571 5572ggml_tensor * out = ggml_trunc ( ctx , a ); 5573ggml_set_name ( out , "out" ); 5574 5575return out ; 5576} 5577 5578void initialize_tensors (ggml_context * ctx ) override { 5579for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5580init_tensor_uniform ( t , -10.0f , 10.0f ); 5581} 5582} 5583}; 5584 5585// GGML_OP_DIAG_MASK_INF 5586struct test_diag_mask_inf : public test_case { 5587const ggml_type type ; 5588const std::array < int64_t, 4 > ne ; 5589const int n_past ; 5590 5591std::string vars () override { 5592return VARS_TO_STR3 ( type , ne , n_past ); 5593} 5594 5595test_diag_mask_inf (ggml_type type = GGML_TYPE_F32 , 5596std::array < int64_t, 4 > ne = { 10 , 10 , 3 , 2 }, 5597int n_past = 5 ) 5598: type ( type ), ne ( ne ), n_past ( n_past ) {} 5599 5600ggml_tensor * build_graph (ggml_context * ctx ) override { 5601ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5602ggml_set_param ( a ); 5603ggml_set_name ( a , "a" ); 5604 5605ggml_tensor * out = ggml_diag_mask_inf ( ctx , a , n_past ); 5606ggml_set_name ( out , "out" ); 5607 5608return out ; 5609} 5610}; 5611 5612// GGML_OP_SOFT_MAX 5613struct test_soft_max : public test_case { 5614const ggml_type type ; 5615const std::array < int64_t, 4 > ne ; 5616const bool mask ; 5617const bool sinks ; 5618const ggml_type m_prec ; 5619const std::array < int64_t, 2 > nr23 ; // broadcast only dims 2 and 3 5620const float scale ; 5621const float max_bias ; 5622const bool inplace ; 5623 5624std::string vars () override { 5625return VARS_TO_STR9 ( type , ne , mask , sinks , m_prec , nr23 , scale , max_bias , inplace ); 5626} 5627 5628// the 1024 test with bias occasionally fails: 5629// SOFT_MAX(type=f32,ne=[1024,16,1,1],mask=1,scale=1.000000,max_bias=8.000000): [SOFT_MAX] NMSE = 0.000000103 > 0.000000100 FAIL 5630virtual double max_nmse_err () override { 5631return 1e-6 ; 5632} 5633 5634test_soft_max (ggml_type type = GGML_TYPE_F32 , 5635std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 5636bool mask = false, 5637bool sinks = false, 5638ggml_type m_prec = GGML_TYPE_F32 , 5639std::array < int64_t, 2 > nr23 = { 1 , 1 }, 5640float scale = 1.0f , 5641float max_bias = 0.0f , 5642bool inplace = false) 5643: type ( type ), ne ( ne ), mask ( mask ), sinks ( sinks ), m_prec ( m_prec ), nr23 ( nr23 ), scale ( scale ), max_bias ( max_bias ), inplace ( inplace ) {} 5644 5645ggml_tensor * build_graph (ggml_context * ctx ) override { 5646ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ] * nr23 [ 0 ], ne [ 3 ] * nr23 [ 1 ]); 5647ggml_set_param ( a ); 5648ggml_set_name ( a , "a" ); 5649 5650ggml_tensor * mask = nullptr ; 5651if ( this -> mask ) { 5652mask = ggml_new_tensor_4d ( ctx , m_prec , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 5653ggml_set_name ( mask , "mask" ); 5654} 5655 5656ggml_tensor * sinks = nullptr ; 5657if ( this -> sinks ) { 5658sinks = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , ne [ 2 ] * nr23 [ 0 ]); 5659ggml_set_name ( sinks , "sinks" ); 5660} 5661 5662ggml_tensor * out ; 5663if ( inplace ) { 5664out = ggml_soft_max_ext_inplace ( ctx , a , mask , scale , max_bias ); 5665} else { 5666out = ggml_soft_max_ext ( ctx , a , mask , scale , max_bias ); 5667} 5668ggml_soft_max_add_sinks ( out , sinks ); 5669ggml_set_name ( out , "out" ); 5670 5671return out ; 5672} 5673 5674bool grad_precise () override { 5675return true; 5676} 5677}; 5678 5679// GGML_OP_SOFT_MAX_BACK 5680struct test_soft_max_back : public test_case { 5681const ggml_type type ; 5682const std::array < int64_t, 4 > ne ; 5683const float scale ; 5684const float max_bias ; 5685 5686std::string vars () override { 5687return VARS_TO_STR4 ( type , ne , scale , max_bias ); 5688} 5689 5690test_soft_max_back (ggml_type type = GGML_TYPE_F32 , 5691std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 5692float scale = 1.0f , 5693float max_bias = 0.0f ) 5694: type ( type ), ne ( ne ), scale ( scale ), max_bias ( max_bias ) {} 5695 5696ggml_tensor * build_graph (ggml_context * ctx ) override { 5697ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5698ggml_set_name ( a , "a" ); 5699 5700ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5701ggml_set_name ( a , "a" ); 5702 5703ggml_tensor * out = ggml_soft_max_ext_back ( ctx , a , b , scale , max_bias ); 5704ggml_set_name ( out , "out" ); 5705 5706return out ; 5707} 5708}; 5709 5710// GGML_OP_ROPE + GGML_OP_ROPE_BACK 5711struct test_rope : public test_case { 5712const ggml_type type ; 5713const std::array < int64_t, 4 > ne_a ; 5714int n_dims ; 5715int mode ; 5716int n_ctx ; // used to generate positions 5717float fs ; // freq_scale 5718float ef ; // ext_factor 5719float af ; // attn_factor 5720bool ff ; 5721int v ; // view (1 : non-contiguous a) 5722bool forward ; 5723bool inplace ; 5724int n_offs ; // offset of the rotated dims window, set via ggml_rope_set_offset() 5725 5726std::string vars () override { 5727// forward can be inferred from the op, does not need to be printed 5728return VARS_TO_STR12 ( type , ne_a , n_dims , mode , n_ctx , fs , ef , af , ff , v , inplace , n_offs ); 5729} 5730 5731test_rope (ggml_type type = GGML_TYPE_F32 , 5732std::array < int64_t, 4 > ne_a = { 10 , 5 , 3 , 1 }, 5733int n_dims = 10 , int mode = GGML_ROPE_TYPE_NORMAL , int n_ctx = 512 , float fs = 1.0f , 5734float ef = 0.0f , float af = 0.0f , bool ff = false, int v = 0 , bool forward = true, bool inplace = false, 5735int n_offs = 0 ) 5736: type ( type ), ne_a ( ne_a ), n_dims ( n_dims ), mode ( mode ), n_ctx ( n_ctx ), fs ( fs ), ef ( ef ), af ( af ), ff ( ff ), v ( v ), forward ( forward ), inplace ( inplace ), n_offs ( n_offs ) {} 5737 5738ggml_tensor * build_graph (ggml_context * ctx ) override { 5739ggml_tensor * a ; 5740if ( v & 1 ) { 5741auto ne = ne_a ; ne [ 0 ] *= 2 ; ne [ 1 ] *= 4 ; ne [ 2 ] *= 3 ; 5742a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5743if ( forward && n_offs == 0 ) { 5744// FIXME: support gradients with n_offs > 0 5745ggml_set_param ( a ); 5746} 5747ggml_set_name ( a , "a" ); 5748 5749a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 5750ggml_set_name ( a , "view_of_a" ); 5751} else if ( v == 2 ) { 5752// second-half slice along dim 0 (mimics build_rope_2d in clip.cpp). 5753// The non-zero view offset (ne_a[0] * elem_size) often produces a 5754// non-aligned buffer offset, which exercises backends' alignment paths. 5755auto ne = ne_a ; ne [ 0 ] *= 2 ; 5756a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 5757if ( forward && n_offs == 0 ) { 5758// FIXME: support gradients with n_offs > 0 5759ggml_set_param ( a ); 5760} 5761ggml_set_name ( a , "a" ); 5762 5763a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], 5764a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 5765ne_a [ 0 ] * ggml_element_size ( a )); 5766ggml_set_name ( a , "view_of_a" ); 5767} else { 5768a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 5769if ( forward && n_offs == 0 ) { 5770// FIXME: support gradients with n_offs > 0 5771ggml_set_param ( a ); 5772} 5773ggml_set_name ( a , "a" ); 5774} 5775 5776const bool is_mrope = mode & GGML_ROPE_TYPE_MROPE ; 5777const bool is_vision = mode == GGML_ROPE_TYPE_VISION ; 5778 5779ggml_tensor * pos ; 5780if ( is_mrope || is_vision ) { 5781pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , ne_a [ 2 ] * 4 ); 5782} else { 5783pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , ne_a [ 2 ]); 5784} 5785ggml_set_name ( pos , "pos" ); 5786 5787ggml_tensor * freq = nullptr ; 5788if ( ff ) { 5789freq = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , n_dims / 2 ); 5790ggml_set_name ( freq , "freq" ); 5791} 5792 5793ggml_tensor * out ; 5794if ( is_mrope ) { 5795if ( is_vision ) { 5796GGML_ASSERT ( n_dims / 4 > 0 ); 5797int rope_sections [ 4 ] = { n_dims / 4 , n_dims / 4 , 0 , 0 }; // Vision-RoPE only use first two dimension for image (x, y) coordinate 5798if ( forward ) { 5799if ( inplace ) { 5800out = ggml_rope_multi_inplace ( ctx , a , pos , freq , n_dims / 2 , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5801} else { 5802out = ggml_rope_multi ( ctx , a , pos , freq , n_dims / 2 , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5803} 5804} else { 5805out = ggml_rope_multi_back ( ctx , a , pos , freq , n_dims / 2 , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5806} 5807} else { 5808GGML_ASSERT ( n_dims / 3 > 0 ); 5809int rope_sections [ 4 ] = { n_dims / 3 , n_dims / 3 , n_dims / 3 , 0 }; 5810if ( forward ) { 5811if ( inplace ) { 5812out = ggml_rope_multi_inplace ( ctx , a , pos , freq , n_dims , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5813} else { 5814out = ggml_rope_multi ( ctx , a , pos , freq , n_dims , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5815} 5816} else { 5817out = ggml_rope_multi_back ( ctx , a , pos , freq , n_dims , rope_sections , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5818} 5819} 5820} else { 5821if ( forward ) { 5822if ( inplace ) { 5823out = ggml_rope_ext_inplace ( ctx , a , pos , freq , n_dims , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5824} else { 5825out = ggml_rope_ext ( ctx , a , pos , freq , n_dims , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5826} 5827} else { 5828out = ggml_rope_ext_back ( ctx , a , pos , freq , n_dims , mode , 0 , 10000.0f , fs , ef , af , 1.0f , 1.0f ); 5829} 5830} 5831if ( n_offs != 0 ) { 5832out = ggml_rope_set_offset ( out , n_offs ); 5833} 5834ggml_set_name ( out , "out" ); 5835 5836return out ; 5837} 5838 5839void initialize_tensors (ggml_context * ctx ) override { 5840for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 5841if ( t -> type == GGML_TYPE_I32 ) { 5842// pos 5843const int num_pos_ids = ( mode & GGML_ROPE_TYPE_MROPE ) ? ne_a [ 2 ] * 4 : ne_a [ 2 ]; 5844std::vector < int > data (num_pos_ids); 5845for (int i = 0 ; i < num_pos_ids ; i ++ ) { 5846data [ i ] = rand () % n_ctx ; 5847} 5848ggml_backend_tensor_set ( t , data . data (), 0 , num_pos_ids * sizeof (int)); 5849} else { 5850if ( t -> ne [ 0 ] == n_dims / 2 ) { 5851// frequency factors in the range [0.9f, 1.1f] 5852init_tensor_uniform ( t , 0.9f , 1.1f ); 5853} else { 5854init_tensor_uniform ( t ); 5855} 5856} 5857} 5858} 5859 5860double max_maa_err () override { 5861return 1e-3 ; 5862} 5863 5864bool grad_precise () override { 5865return true; 5866} 5867}; 5868 5869// GGML_OP_POOL2D 5870struct test_pool2d : public test_case { 5871enum ggml_op_pool pool_type ; 5872const ggml_type type_input ; 5873const std::array < int64_t, 4 > ne_input ; 5874// kernel size 5875const int k0 ; 5876const int k1 ; 5877// stride 5878const int s0 ; 5879const int s1 ; 5880// padding 5881const int p0 ; 5882const int p1 ; 5883 5884std::string vars () override { 5885return VARS_TO_STR9 ( pool_type , type_input , ne_input , k0 , k1 , s0 , s1 , p0 , p1 ); 5886} 5887 5888test_pool2d (ggml_op_pool pool_type = GGML_OP_POOL_AVG , 5889ggml_type type_input = GGML_TYPE_F32 , 5890std::array < int64_t, 4 > ne_input = { 10 , 10 , 3 , 1 }, // [input_width, input_height, input_channels, 1] 5891int k0 = 3 , int k1 = 3 , 5892int s0 = 1 , int s1 = 1 , 5893int p0 = 1 , int p1 = 1 ) 5894: pool_type ( pool_type ), type_input ( type_input ), ne_input ( ne_input ), k0 ( k0 ), k1 ( k1 ), s0 ( s0 ), s1 ( s1 ), p0 ( p0 ), p1 ( p1 ) {} 5895 5896ggml_tensor * build_graph (ggml_context * ctx ) override { 5897ggml_tensor * input = ggml_new_tensor ( ctx , type_input , 4 , ne_input . data ()); 5898ggml_set_param ( input ); 5899ggml_set_name ( input , "input" ); 5900 5901ggml_tensor * out = ggml_pool_2d ( ctx , input , pool_type , k0 , k1 , s0 , s1 , p0 , p1 ); 5902ggml_set_name ( out , "out" ); 5903 5904return out ; 5905} 5906}; 5907 5908// GGML_OP_POOL1D 5909struct test_pool1d : public test_case { 5910enum ggml_op_pool pool_type ; 5911const ggml_type type_input ; 5912const std::array < int64_t, 4 > ne_input ; 5913const int k0 ; 5914const int s0 ; 5915const int p0 ; 5916 5917std::string vars () override { 5918return VARS_TO_STR6 ( pool_type , type_input , ne_input , k0 , s0 , p0 ); 5919} 5920 5921test_pool1d (ggml_op_pool pool_type = GGML_OP_POOL_AVG , 5922ggml_type type_input = GGML_TYPE_F32 , 5923std::array < int64_t, 4 > ne_input = { 10 , 1 , 1 , 1 }, 5924int k0 = 3 , int s0 = 3 , int p0 = 0 ) 5925: pool_type ( pool_type ), type_input ( type_input ), ne_input ( ne_input ), k0 ( k0 ), s0 ( s0 ), p0 ( p0 ) {} 5926 5927ggml_tensor * build_graph (ggml_context * ctx ) override { 5928ggml_tensor * input = ggml_new_tensor ( ctx , type_input , 4 , ne_input . data ()); 5929ggml_set_param ( input ); 5930ggml_set_name ( input , "input" ); 5931 5932ggml_tensor * out = ggml_pool_1d ( ctx , input , pool_type , k0 , s0 , p0 ); 5933ggml_set_name ( out , "out" ); 5934 5935return out ; 5936} 5937}; 5938 5939// GGML_OP_CONV_TRANSPOSE_1D 5940struct test_conv_transpose_1d : public test_case { 5941const std::array < int64_t, 4 > ne_input ; 5942const std::array < int64_t, 4 > ne_kernel ; 5943 5944const int s0 ; // stride 5945const int p0 ; // padding 5946const int d0 ; // dilation 5947 5948std::string vars () override { 5949return VARS_TO_STR5 ( ne_input , ne_kernel , s0 , p0 , d0 ); 5950} 5951 5952test_conv_transpose_1d (std::array < int64_t, 4 > ne_input = { 197 , 32 , 1 , 1 }, // [input_width, input_channels, 1 /* assert in cpu kernel*/, 1 (should be batch)] 5953std::array < int64_t, 4 > ne_kernel = { 16 , 32 , 32 , 1 }, // [kernel_width, output_channels, input_channels, 1 (should be batch)] 5954int s0 = 1 , int p0 = 0 , int d0 = 1 ) 5955: ne_input ( ne_input ), ne_kernel ( ne_kernel ), s0 ( s0 ), p0 ( p0 ), d0 ( d0 ) {} 5956 5957ggml_tensor * build_graph (ggml_context * ctx ) override { 5958ggml_tensor * input = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_input . data ()); 5959ggml_set_name ( input , "input" ); 5960 5961ggml_tensor * kernel = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_kernel . data ()); 5962ggml_set_name ( kernel , "kernel" ); 5963 5964ggml_tensor * out = ggml_conv_transpose_1d ( ctx , kernel , input , s0 , p0 , d0 ); 5965ggml_set_name ( out , "out" ); 5966 5967return out ; 5968} 5969}; 5970 5971// GGML_OP_COL2IM_1D 5972struct test_col2im_1d : public test_case { 5973const ggml_type type ; 5974const int64_t K ; // kernel size 5975const int64_t OC ; // output channels 5976const int64_t T_in ; // input length (number of columns) 5977const int s0 ; // stride 5978const int p0 ; // padding cropped from both sides 5979 5980std::string vars () override { 5981return VARS_TO_STR6 ( type , K , OC , T_in , s0 , p0 ); 5982} 5983 5984double max_nmse_err () override { 5985return type == GGML_TYPE_F32 ? 1e-7 : 5e-4 ; 5986} 5987 5988test_col2im_1d (ggml_type type = GGML_TYPE_F32 , 5989int64_t K = 4 , int64_t OC = 3 , int64_t T_in = 7 , 5990int s0 = 2 , int p0 = 0 ) 5991: type ( type ), K ( K ), OC ( OC ), T_in ( T_in ), s0 ( s0 ), p0 ( p0 ) {} 5992 5993ggml_tensor * build_graph (ggml_context * ctx ) override { 5994ggml_tensor * cols = ggml_new_tensor_2d ( ctx , type , K * OC , T_in ); 5995ggml_set_name ( cols , "cols" ); 5996 5997ggml_tensor * out = ggml_col2im_1d ( ctx , cols , s0 , (int) OC , p0 ); 5998ggml_set_name ( out , "out" ); 5999 6000return out ; 6001} 6002}; 6003 6004// GGML_OP_CONV_TRANSPOSE_2D 6005struct test_conv_transpose_2d : public test_case { 6006// Dimensions 6007const std::array < int64_t, 4 > ne_input ; 6008const std::array < int64_t, 4 > ne_kernel ; 6009const int stride ; 6010// Types 6011const ggml_type kernel_type ; 6012 6013std::string vars () override { 6014return VARS_TO_STR4 ( kernel_type , ne_input , ne_kernel , stride ); 6015} 6016 6017double max_nmse_err () override { 6018return 5e-4 ; // The default 1e-7 is too small for Vulkan. 6019} 6020 6021test_conv_transpose_2d ( 6022std::array < int64_t, 4 > ne_input = { 10 , 10 , 3 , 1 }, // [input_width, input_height, input_channels, 1] 6023std::array < int64_t, 4 > ne_kernel = { 3 , 3 , 3 , 1 }, // [kernel_width, kernel_height, input_channels, 1] 6024int stride = 1 , 6025ggml_type kernel_type = GGML_TYPE_F16 6026) : ne_input ( ne_input ), ne_kernel ( ne_kernel ), stride ( stride ), kernel_type ( kernel_type ) {} 6027 6028ggml_tensor * build_graph (ggml_context * ctx ) override { 6029ggml_tensor * input = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_input . data ()); 6030ggml_set_name ( input , "input" ); 6031 6032ggml_tensor * kernel = ggml_new_tensor ( ctx , kernel_type , 4 , ne_kernel . data ()); 6033ggml_set_name ( kernel , "kernel" ); 6034 6035ggml_tensor * out = ggml_conv_transpose_2d_p0 ( ctx , kernel , input , stride ); 6036ggml_set_name ( out , "out" ); 6037 6038return out ; 6039} 6040}; 6041 6042// GGML_OP_IM2COL 6043struct test_im2col : public test_case { 6044const ggml_type type_input ; 6045const ggml_type type_kernel ; 6046const ggml_type dst_type ; 6047const std::array < int64_t, 4 > ne_input ; 6048const std::array < int64_t, 4 > ne_kernel ; 6049// stride 6050const int s0 ; 6051const int s1 ; 6052// padding 6053const int p0 ; 6054const int p1 ; 6055// dilation 6056const int d0 ; 6057const int d1 ; 6058// mode 6059const bool is_2D ; 6060 6061std::string vars () override { 6062return VARS_TO_STR12 ( type_input , type_kernel , dst_type , ne_input , ne_kernel , s0 , s1 , p0 , p1 , d0 , d1 , is_2D ); 6063} 6064 6065test_im2col (ggml_type type_input = GGML_TYPE_F32 , ggml_type type_kernel = GGML_TYPE_F16 , ggml_type dst_type = GGML_TYPE_F32 , 6066std::array < int64_t, 4 > ne_input = { 10 , 10 , 3 , 1 }, // [input_width, input_height, input_channels, 1] 6067std::array < int64_t, 4 > ne_kernel = { 3 , 3 , 3 , 1 }, // [kernel_width, kernel_height, input_channels, 1] 6068int s0 = 1 , int s1 = 1 , 6069int p0 = 1 , int p1 = 1 , 6070int d0 = 1 , int d1 = 1 , 6071bool is_2D = true) 6072: type_input ( type_input ), type_kernel ( type_kernel ), dst_type ( dst_type ), ne_input ( ne_input ), ne_kernel ( ne_kernel ), s0 ( s0 ), s1 ( s1 ), p0 ( p0 ), p1 ( p1 ), d0 ( d0 ), d1 ( d1 ), is_2D ( is_2D ) {} 6073 6074ggml_tensor * build_graph (ggml_context * ctx ) override { 6075ggml_tensor * input = ggml_new_tensor ( ctx , type_input , 4 , ne_input . data ()); 6076ggml_set_param ( input ); 6077ggml_set_name ( input , "input" ); 6078 6079ggml_tensor * kernel = ggml_new_tensor ( ctx , type_kernel , 4 , ne_kernel . data ()); 6080ggml_set_name ( kernel , "kernel" ); 6081 6082ggml_tensor * out = ggml_im2col ( ctx , kernel , input , s0 , s1 , p0 , p1 , d0 , d1 , is_2D , dst_type ); 6083ggml_set_name ( out , "out" ); 6084 6085return out ; 6086} 6087}; 6088 6089// GGML_OP_IM2COL_3D 6090struct test_im2col_3d : public test_case { 6091const ggml_type type_input ; 6092const ggml_type type_kernel ; 6093const ggml_type dst_type ; 6094const std::array < int64_t, 4 > ne_input ; 6095const std::array < int64_t, 4 > ne_kernel ; 6096// stride 6097const int s0 ; 6098const int s1 ; 6099const int s2 ; 6100// padding 6101const int p0 ; 6102const int p1 ; 6103const int p2 ; 6104// dilation 6105const int d0 ; 6106const int d1 ; 6107const int d2 ; 6108 6109const int64_t IC ; 6110const bool v ; 6111 6112std::string vars () override { 6113return VARS_TO_STR16 ( type_input , type_kernel , dst_type , ne_input , ne_kernel , IC , s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 , v ); 6114} 6115 6116test_im2col_3d (ggml_type type_input = GGML_TYPE_F32 , ggml_type type_kernel = GGML_TYPE_F16 , ggml_type dst_type = GGML_TYPE_F32 , 6117std::array < int64_t, 4 > ne_input = { 10 , 10 , 10 , 9 }, // [OC*IC, KD, KH, KW] 6118std::array < int64_t, 4 > ne_kernel = { 3 , 3 , 3 , 1 }, // [N*IC, ID, IH, IW] 6119int64_t IC = 3 , 6120int s0 = 1 , int s1 = 1 , int s2 = 1 , 6121int p0 = 1 , int p1 = 1 , int p2 = 1 , 6122int d0 = 1 , int d1 = 1 , int d2 = 1 , 6123bool v = false) 6124: type_input ( type_input ), type_kernel ( type_kernel ), dst_type ( dst_type ), ne_input ( ne_input ), ne_kernel ( ne_kernel ), s0 ( s0 ), s1 ( s1 ), s2 ( s2 ), p0 ( p0 ), p1 ( p1 ), p2 ( p2 ), d0 ( d0 ), d1 ( d1 ), d2 ( d2 ), IC ( IC ), v ( v ) {} 6125 6126ggml_tensor * build_graph (ggml_context * ctx ) override { 6127ggml_tensor * input = ggml_new_tensor ( ctx , type_input , 4 , ne_input . data ()); 6128ggml_set_param ( input ); 6129ggml_set_name ( input , "input" ); 6130 6131if ( v ) { 6132input = ggml_view_4d ( ctx , input , ne_input [ 0 ] - 2 , ne_input [ 1 ] - 2 , ne_input [ 2 ] - 2 , ne_input [ 3 ] - 2 , input -> nb [ 1 ], input -> nb [ 2 ], input -> nb [ 3 ], 0 ); 6133ggml_set_name ( input , "view_of_input" ); 6134} 6135 6136ggml_tensor * kernel = ggml_new_tensor ( ctx , type_kernel , 4 , ne_kernel . data ()); 6137ggml_set_name ( kernel , "kernel" ); 6138 6139ggml_tensor * out = ggml_im2col_3d ( ctx , kernel , input , IC , s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 , dst_type ); 6140ggml_set_name ( out , "out" ); 6141 6142return out ; 6143} 6144}; 6145 6146// CONV_2D 6147struct test_conv_2d : public test_case { 6148const std::array < int64_t, 4 > ne_input ; 6149const std::array < int64_t, 4 > ne_kernel ; 6150const ggml_type type_kernel ; 6151const int stride0 ; 6152const int stride1 ; 6153const int padding0 ; 6154const int padding1 ; 6155const int dilation0 ; 6156const int dilation1 ; 6157// Whether the inputs are contiguous in the channel dim or the width dim 6158const bool cwhn ; 6159 6160// If true, the direct CONV_2D will be used in the graph, otherwise it 6161// uses ggml_conv_2d: 6162// * if the program is called with -o CONV_2D_DIRECT_IMPL, the 6163// CONV_2D graph will be built, while 6164// * if the program is called with -o CONV_2D_INDIRECT_IMPL, the 6165// IM2COL -> MUL_MM graph will be built. 6166 6167std::string vars () override { 6168return VARS_TO_STR10 ( ne_input , ne_kernel , type_kernel , stride0 , stride1 , padding0 , padding1 , dilation0 , dilation1 , cwhn ); 6169} 6170 6171double max_nmse_err () override { 6172return 5e-4 ; 6173} 6174 6175uint64_t op_flops (ggml_tensor * t ) override { 6176GGML_UNUSED ( t ); 6177// Just counting matmul costs: 6178// KxCRS @ CRSxNPQ = KxNPQ --> KxNPQx(CRS+CRS-1) flops 6179 6180// Copied from ggml.c: int64_t ggml_calc_conv_output_size(int64_t ins, int64_t ks, int s, int p, int d) 6181auto calc_conv_output_size = [](int64_t ins , int64_t ks , int s , int p , int d ) -> int64_t { 6182return ( ins + 2 * p - d * ( ks - 1 ) - 1 ) / s + 1 ; 6183}; 6184 6185int64_t W = ne_input [ 0 ]; 6186int64_t H = ne_input [ 1 ]; 6187int64_t KW = ne_kernel [ 0 ]; 6188int64_t KH = ne_kernel [ 1 ]; 6189int64_t Cin = ne_kernel [ 2 ]; 6190int64_t Cout = ne_kernel [ 3 ]; 6191int64_t N = ne_input [ 3 ]; 6192int64_t OH = calc_conv_output_size ( H , KH , stride0 , padding0 , dilation0 ); 6193int64_t OW = calc_conv_output_size ( W , KW , stride0 , padding0 , dilation0 ); 6194 6195int64_t K = Cout ; 6196int64_t CRS = Cin * KH * KW ; 6197int64_t NPQ = N * OH * OW ; 6198 6199return K * NPQ * ( 2 * CRS - 1 ); 6200} 6201 6202test_conv_2d (std::array < int64_t, 4 > ne_input = { 64 , 64 , 16 , 1 }, 6203std::array < int64_t, 4 > ne_kernel = { 3 , 3 , 1 , 16 }, ggml_type type_kernel = GGML_TYPE_F32 , int stride0 = 1 , 6204int stride1 = 1 , int padding0 = 0 , int padding1 = 0 , int dilation0 = 1 , int dilation1 = 1 , bool cwhn = false) : 6205ne_input ( ne_input ), 6206ne_kernel ( ne_kernel ), 6207type_kernel ( type_kernel ), 6208stride0 ( stride0 ), 6209stride1 ( stride1 ), 6210padding0 ( padding0 ), 6211padding1 ( padding1 ), 6212dilation0 ( dilation0 ), 6213dilation1 ( dilation1 ), 6214cwhn ( cwhn ) {} 6215 6216ggml_tensor * build_graph (ggml_context * ctx ) override { 6217ggml_tensor * input = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_input . data ()); 6218ggml_set_name ( input , "input" ); 6219 6220ggml_tensor * kernel = ggml_new_tensor ( ctx , type_kernel , 4 , ne_kernel . data ()); 6221ggml_set_name ( kernel , "kernel" ); 6222 6223if ( cwhn ) { 6224// change memory layout to channel-most-contiguous (CWHN), 6225// then permute it back so NE matches the original input 6226input = ggml_cont ( ctx , ggml_permute ( ctx , input , 1 , 2 , 0 , 3 )); 6227input = ggml_permute ( ctx , input , 2 , 0 , 1 , 3 ); 6228kernel = ggml_cont ( ctx , ggml_permute ( ctx , kernel , 2 , 3 , 1 , 0 )); 6229kernel = ggml_permute ( ctx , kernel , 3 , 2 , 0 , 1 ); 6230} 6231 6232ggml_tensor * out = 6233ggml_conv_2d_direct ( ctx , kernel , input , stride0 , stride1 , padding0 , padding1 , dilation0 , dilation1 ); 6234ggml_set_name ( out , "out" ); 6235return out ; 6236} 6237}; 6238 6239// GGML_OP_CONV_2D_DW 6240struct test_conv_2d_dw : public test_case { 6241const std::array < int64_t, 4 > ne_input ; 6242const std::array < int64_t, 4 > ne_kernel ; 6243const ggml_type type_kernel ; 6244const int stride ; 6245const int padding ; 6246const int dilation ; 6247const bool cwhn ; 6248 6249std::string vars () override { 6250return VARS_TO_STR7 ( ne_input , ne_kernel , type_kernel , stride , padding , dilation , cwhn ); 6251} 6252 6253test_conv_2d_dw ( 6254std::array < int64_t, 4 > ne_input = { 64 , 64 , 16 , 1 }, 6255std::array < int64_t, 4 > ne_kernel = { 3 , 3 , 1 , 16 }, 6256ggml_type type_kernel = GGML_TYPE_F32 , 6257int stride = 1 , int padding = 0 , int dilation = 1 , bool cwhn = false) 6258: ne_input ( ne_input ), ne_kernel ( ne_kernel ), type_kernel ( type_kernel ), stride ( stride ), padding ( padding ), dilation ( dilation ), cwhn ( cwhn ) {} 6259 6260ggml_tensor * build_graph (ggml_context * ctx ) override { 6261ggml_tensor * input = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_input . data ()); 6262ggml_set_name ( input , "input" ); 6263 6264ggml_tensor * kernel = ggml_new_tensor ( ctx , type_kernel , 4 , ne_kernel . data ()); 6265ggml_set_name ( kernel , "kernel" ); 6266 6267if ( cwhn ) { 6268// change memory layout to channel-most-contiguous (CWHN), 6269// then permute it back so NE matches the original input 6270input = ggml_cont ( ctx , ggml_permute ( ctx , input , 1 , 2 , 0 , 3 )); 6271input = ggml_permute ( ctx , input , 2 , 0 , 1 , 3 ); 6272kernel = ggml_cont ( ctx , ggml_permute ( ctx , kernel , 2 , 3 , 1 , 0 )); 6273kernel = ggml_permute ( ctx , kernel , 3 , 2 , 0 , 1 ); 6274} 6275 6276ggml_tensor * out = ggml_conv_2d_dw_direct ( 6277ctx , kernel , input , 6278stride , stride , padding , padding , dilation , dilation ); 6279ggml_set_name ( out , "out" ); 6280return out ; 6281} 6282}; 6283 6284// GGML_OP_CONV_3D 6285struct test_conv_3d : public test_case { 6286// Logical 5D dimensions 6287const int64_t N , IC , ID , IH , IW ; 6288const int64_t OC , KD , KH , KW ; 6289// Conv params 6290const int s0 , s1 , s2 ; 6291const int p0 , p1 , p2 ; 6292const int d0 , d1 , d2 ; 6293// Types 6294const ggml_type type_kernel ; 6295 6296std::string op_desc (ggml_tensor * t ) override { 6297GGML_UNUSED ( t ); 6298return "CONV_3D" ; 6299} 6300 6301std::string vars () override { 6302return VARS_TO_STR11 ( N , IC , ID , IH , IW , OC , KD , KH , KW , s0 , s1 ) + "," + 6303VARS_TO_STR8 ( s2 , p0 , p1 , p2 , d0 , d1 , d2 , type_kernel ); 6304} 6305 6306double max_nmse_err () override { 6307return 5e-4 ; 6308} 6309 6310uint64_t op_flops (ggml_tensor * t ) override { 6311GGML_UNUSED ( t ); 6312auto calc_conv_output_size = [](int64_t ins , int64_t ks , int s , int p , int d ) -> int64_t { 6313return ( ins + 2 * p - d * ( ks - 1 ) - 1 ) / s + 1 ; 6314}; 6315const int64_t OD = calc_conv_output_size ( ID , KD , s2 , p2 , d2 ); 6316const int64_t OH = calc_conv_output_size ( IH , KH , s1 , p1 , d1 ); 6317const int64_t OW = calc_conv_output_size ( IW , KW , s0 , p0 , d0 ); 6318 6319return (uint64_t) N * OC * OD * OH * OW * ( 2 * IC * KD * KH * KW - 1 ); 6320} 6321 6322test_conv_3d ( 6323int64_t N , int64_t IC , int64_t ID , int64_t IH , int64_t IW , 6324int64_t OC , int64_t KD , int64_t KH , int64_t KW , 6325int s0 , int s1 , int s2 , 6326int p0 , int p1 , int p2 , 6327int d0 , int d1 , int d2 , 6328ggml_type type_kernel 6329) : N ( N ), IC ( IC ), ID ( ID ), IH ( IH ), IW ( IW ), 6330OC ( OC ), KD ( KD ), KH ( KH ), KW ( KW ), 6331s0 ( s0 ), s1 ( s1 ), s2 ( s2 ), 6332p0 ( p0 ), p1 ( p1 ), p2 ( p2 ), 6333d0 ( d0 ), d1 ( d1 ), d2 ( d2 ), 6334type_kernel ( type_kernel ) {} 6335 6336ggml_tensor * build_graph (ggml_context * ctx ) override { 6337// GGML input tensor is packed as [W, H, D, C*N] 6338const int64_t ne_input [] = { IW , IH , ID , IC * N }; 6339ggml_tensor * input = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne_input ); 6340ggml_set_name ( input , "input" ); 6341 6342// GGML kernel tensor is packed as [KW, KH, KD, IC*OC] 6343const int64_t ne_kernel [] = { KW , KH , KD , IC * OC }; 6344ggml_tensor * kernel = ggml_new_tensor ( ctx , type_kernel , 4 , ne_kernel ); 6345ggml_set_name ( kernel , "kernel" ); 6346 6347ggml_tensor * out = ggml_conv_3d_direct ( ctx , kernel , input , s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 , (int) IC , (int) N , (int) OC ); 6348ggml_set_name ( out , "out" ); 6349return out ; 6350} 6351}; 6352 6353// GGML_OP_CONCAT 6354struct test_concat : public test_case { 6355const ggml_type type ; 6356const std::array < int64_t, 4 > ne_a ; 6357const int64_t ne_b_d ; 6358const int dim ; 6359const int v ; // view (1 << 0: non-cont a (first 3 dim), 1 << 1: non-cont b (first 3 dim), 1 << 2: non-cont a (last 2 dim), 1 << 3: non-cont b (last 2 dim)) 6360 6361std::string vars () override { 6362return VARS_TO_STR5 ( type , ne_a , ne_b_d , dim , v ); 6363} 6364 6365test_concat (ggml_type type = GGML_TYPE_F32 , 6366std::array < int64_t, 4 > ne_a = { 10 , 5 , 5 , 5 }, 6367int64_t ne_b_d = 5 , 6368int dim = 2 , int v = 0 ) 6369: type ( type ), ne_a ( ne_a ), ne_b_d ( ne_b_d ), dim ( dim ), v ( v ) {} 6370 6371ggml_tensor * build_graph (ggml_context * ctx ) override { 6372auto ne_b = ne_a ; 6373ne_b [ dim ] = ne_b_d ; 6374ggml_tensor * a ; 6375if ( v & 1 ) { 6376auto ne = ne_a ; ne [ 0 ] *= 2 ; ne [ 1 ] *= 4 ; ne [ 2 ] *= 3 ; 6377a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6378ggml_set_name ( a , "a" ); 6379 6380a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 6381ggml_set_name ( a , "view_of_a" ); 6382} else if ( v & 4 ) { 6383auto ne = ne_a ; ne [ 2 ] *= 2 ; ne [ 3 ] *= 4 ; 6384a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6385ggml_set_name ( a , "a" ); 6386 6387a = ggml_view_4d ( ctx , a , ne_a [ 0 ], ne_a [ 1 ], ne_a [ 2 ], ne_a [ 3 ], a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 6388ggml_set_name ( a , "view_of_a" ); 6389} else { 6390a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 6391ggml_set_name ( a , "a" ); 6392} 6393ggml_tensor * b ; 6394if ( v & 2 ) { 6395auto ne = ne_b ; ne [ 0 ] *= 3 ; ne [ 1 ] *= 2 ; ne [ 2 ] *= 4 ; 6396b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6397ggml_set_name ( b , "b" ); 6398 6399b = ggml_view_4d ( ctx , b , ne_b [ 0 ], ne_b [ 1 ], ne_b [ 2 ], ne_b [ 3 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 6400ggml_set_name ( b , "view_of_b" ); 6401} else if ( v & 8 ) { 6402auto ne = ne_b ; ne [ 2 ] *= 3 ; ne [ 3 ] *= 2 ; 6403b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6404ggml_set_name ( b , "b" ); 6405 6406b = ggml_view_4d ( ctx , b , ne_b [ 0 ], ne_b [ 1 ], ne_b [ 2 ], ne_b [ 3 ], b -> nb [ 1 ], b -> nb [ 2 ], b -> nb [ 3 ], 0 ); 6407ggml_set_name ( b , "view_of_b" ); 6408} else { 6409b = ggml_new_tensor ( ctx , type , 4 , ne_b . data ()); 6410ggml_set_name ( b , "b" ); 6411} 6412 6413ggml_tensor * out = ggml_concat ( ctx , a , b , dim ); 6414ggml_set_name ( out , "out" ); 6415 6416return out ; 6417} 6418}; 6419 6420// GGML_OP_ARGSORT 6421struct test_argsort : public test_case { 6422const ggml_type type ; 6423const std::array < int64_t, 4 > ne ; 6424ggml_sort_order order ; 6425 6426std::string vars () override { 6427return VARS_TO_STR3 ( type , ne , order ); 6428} 6429 6430test_argsort (ggml_type type = GGML_TYPE_F32 , 6431std::array < int64_t, 4 > ne = { 16 , 10 , 10 , 10 }, 6432ggml_sort_order order = GGML_SORT_ORDER_ASC ) 6433: type ( type ), ne ( ne ), order ( order ) {} 6434 6435ggml_tensor * build_graph (ggml_context * ctx ) override { 6436ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6437ggml_set_name ( a , "a" ); 6438 6439ggml_tensor * out = ggml_argsort ( ctx , a , order ); 6440ggml_set_name ( out , "out" ); 6441 6442return out ; 6443} 6444 6445void initialize_tensors (ggml_context * ctx ) override { 6446std::random_device rd ; 6447std::default_random_engine rng ( rd ()); 6448for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 6449if ( t -> type == GGML_TYPE_I32 ) { 6450// indices 6451std::vector < int > data ( ggml_nelements ( t )); 6452for (int i = 0 ; i < ggml_nelements ( t ); i ++ ) { 6453data [ i ] = rand (); 6454} 6455std:: shuffle ( data . begin (), data . end (), rng ); 6456ggml_backend_tensor_set ( t , data . data (), 0 , ne [ 0 ] * ne [ 1 ] * ne [ 2 ] * ne [ 3 ] * sizeof (int)); 6457} else if ( t -> type == GGML_TYPE_F32 ) { 6458// initialize with unique values to avoid ties 6459for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 6460std::vector < float > data ( t -> ne [ 0 ]); 6461for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 6462data [ i ] = i ; 6463} 6464std:: shuffle ( data . begin (), data . end (), rng ); 6465ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (float)); 6466} 6467} else { 6468GGML_ABORT ( "fatal error" ); 6469} 6470} 6471} 6472}; 6473 6474// GGML_OP_TOP_K 6475struct test_top_k : public test_case { 6476const ggml_type type ; 6477const std::array < int64_t, 4 > ne ; 6478const int k ; 6479const bool ties ; 6480ggml_tensor * input {}; 6481 6482std::string vars () override { 6483return VARS_TO_STR4 ( type , ne , k , ties ); 6484} 6485 6486test_top_k (ggml_type type = GGML_TYPE_F32 , 6487std::array < int64_t, 4 > ne = { 16 , 10 , 10 , 10 }, 6488int k = 4 , bool ties = false) 6489: type ( type ), ne ( ne ), k ( k ), ties ( ties ) {} 6490 6491double max_err () override { 6492return 0.0 ; 6493} 6494 6495// When there are ties, only validate the final result. 6496// The logic in err can't handle the sentinel tensors. 6497bool run_whole_graph () override { return ties ; } 6498 6499double err ( const float * a , const float * b , size_t n ) override { 6500// When there are no ties, we expect the exact same set of indices, 6501// but possibly in a different order. When there are ties, the indices 6502// can be different but the input values they correspond to should be 6503// the same. The logic for ties could work for non-ties, but only for 6504// the output tensor, not for the sentinel tensors. 6505if ( ties ) { 6506std::vector < float > src ( ggml_nelements ( input )); 6507 6508ggml_backend_tensor_get ( input , src . data (), 0 , ggml_nelements ( input ) * ggml_type_size ( type )); 6509 6510double diff = 0.0f ; 6511 6512GGML_ASSERT ( n == (size_t)( ggml_nrows ( input ) * k )); 6513int64_t cols = input -> ne [ 0 ]; 6514std::vector < int32_t > ia (k); 6515std::vector < int32_t > ib (k); 6516std::vector < float > asrc (k); 6517std::vector < float > bsrc (k); 6518for (int64_t r = 0 ; r < ggml_nrows ( input ); r ++ ) { 6519// Convert indices for the row back to integer 6520for (int64_t c = 0 ; c < k ; c ++ ) { 6521ia [ c ] = (int32_t) a [ r * k + c ]; 6522ib [ c ] = (int32_t) b [ r * k + c ]; 6523} 6524// The src values for each row should match. 6525for (int64_t c = 0 ; c < k ; c ++ ) { 6526asrc [ c ] = src [ r * cols + ia [ c ]]; 6527bsrc [ c ] = src [ r * cols + ib [ c ]]; 6528} 6529diff += jdst ( asrc . data (), bsrc . data (), k ); 6530// There should be no duplicate indices 6531std:: sort ( ia . begin (), ia . end ()); 6532std:: sort ( ib . begin (), ib . end ()); 6533if (std:: adjacent_find ( ia . begin (), ia . end ()) != ia . end ()) { 6534diff += 1 ; 6535} 6536if (std:: adjacent_find ( ib . begin (), ib . end ()) != ib . end ()) { 6537diff += 1 ; 6538} 6539} 6540return diff ; 6541} else { 6542std::vector < int32_t > ia (n); 6543std::vector < int32_t > ib (n); 6544 6545double diff = 0.0f ; 6546 6547for (size_t i = 0 ; i < n ; i ++ ) { 6548ia [ i ] = (int32_t) a [ i ]; 6549ib [ i ] = (int32_t) b [ i ]; 6550 6551// penalize the result if the data is not integer valued 6552diff += std:: fabs ( a [ i ] - ia [ i ]); 6553diff += std:: fabs ( b [ i ] - ib [ i ]); 6554} 6555 6556return diff + jdst ( ia . data (), ib . data (), n ); 6557} 6558} 6559 6560ggml_tensor * build_graph (ggml_context * ctx ) override { 6561ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 6562ggml_set_name ( a , "a" ); 6563 6564// Save 'a' for err() 6565input = a ; 6566 6567ggml_tensor * out = ggml_top_k ( ctx , a , k ); 6568ggml_set_name ( out , "out" ); 6569 6570return out ; 6571} 6572 6573void initialize_tensors (ggml_context * ctx ) override { 6574std::random_device rd ; 6575std::default_random_engine rng ( rd ()); 6576for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 6577int tie_denom = std:: max ( 1 , std:: min ( 10 , k / 2 )); 6578for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 6579std::vector < float > data ( t -> ne [ 0 ]); 6580for (int i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 6581if ( ties ) { 6582// integer division to introduce duplicates 6583data [ i ] = i / tie_denom ; 6584} else { 6585data [ i ] = i ; 6586} 6587} 6588std:: shuffle ( data . begin (), data . end (), rng ); 6589ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (float)); 6590} 6591} 6592} 6593}; 6594 6595// qwen4exp QSA indexer top-k fusion: expand per-block scores to cells, add the f16 mask, top-k. 6596struct test_topk_qsa : public test_case { 6597const int64_t n_blocks ; 6598const int64_t n_kv ; 6599const int64_t n_tps ; 6600const int64_t n_stream ; 6601const int width ; 6602ggml_tensor * out {}; 6603 6604std::string op_desc (ggml_tensor * t ) override { 6605GGML_UNUSED ( t ); 6606return "TOPK_QSA" ; 6607} 6608 6609std::string vars () override { 6610return VARS_TO_STR5 ( n_blocks , n_kv , n_tps , n_stream , width ); 6611} 6612 6613test_topk_qsa (int64_t n_blocks = 512 , int64_t n_kv = 2048 , int64_t n_tps = 2 , int64_t n_stream = 1 , int width = 1500 ) 6614: n_blocks ( n_blocks ), n_kv ( n_kv ), n_tps ( n_tps ), n_stream ( n_stream ), width ( width ) {} 6615 6616double max_err () override { return 0.0 ; } 6617bool run_whole_graph () override { return true; } 6618 6619ggml_tensor * build_graph (ggml_context * ctx ) override { 6620ggml_tensor * score = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , n_blocks , n_tps , n_stream ); 6621ggml_set_name ( score , "score" ); 6622ggml_tensor * cell_blk = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , n_kv , n_stream ); 6623ggml_set_name ( cell_blk , "cell_blk" ); 6624ggml_tensor * kq_mask = ggml_new_tensor_3d ( ctx , GGML_TYPE_F16 , n_kv , n_tps , n_stream ); 6625ggml_set_name ( kq_mask , "kq_mask" ); 6626 6627ggml_tensor * a = ggml_cont ( ctx , ggml_permute ( ctx , score , 1 , 0 , 2 , 3 )); 6628ggml_tensor * e = ggml_get_rows ( ctx , a , cell_blk ); 6629e = ggml_cont ( ctx , ggml_permute ( ctx , e , 1 , 0 , 2 , 3 )); 6630ggml_tensor * m = ggml_cast ( ctx , kq_mask , GGML_TYPE_F32 ); 6631e = ggml_add ( ctx , e , ggml_reshape_3d ( ctx , m , n_kv , n_tps , n_stream )); 6632out = ggml_top_k ( ctx , e , width ); 6633ggml_set_name ( out , "out" ); 6634return out ; 6635} 6636 6637std::vector < ggml_tensor *> fusion_test_nodes () override { return { out }; } 6638 6639// distinct mask ramp + small scores keep every cell value unique, so no top-k ties 6640void initialize_tensors (ggml_context * ctx ) override { 6641for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 6642if ( t -> op != GGML_OP_NONE ) { 6643continue ; 6644} 6645if ( t -> type == GGML_TYPE_I32 ) { 6646std::vector < int32_t > data ( ggml_nelements ( t )); 6647for (auto & v : data ) { v = rand () % n_blocks ; } 6648ggml_backend_tensor_set ( t , data . data (), 0 , data . size () * sizeof (int32_t)); 6649} else if ( t -> type == GGML_TYPE_F16 ) { 6650std::vector < ggml_fp16_t > data ( ggml_nelements ( t )); 6651for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 6652for (int64_t i = 0 ; i < n_kv ; i ++ ) { 6653data [ r * n_kv + i ] = ggml_fp32_to_fp16 ((float) i ); 6654} 6655} 6656ggml_backend_tensor_set ( t , data . data (), 0 , data . size () * sizeof ( ggml_fp16_t )); 6657} else { 6658init_tensor_uniform ( t , 0.0f , 0.5f ); 6659} 6660} 6661} 6662 6663// top-k output order is unspecified; compare as a set of indices 6664double err ( const float * a , const float * b , size_t n ) override { 6665std::vector < int32_t > ia (n), ib (n); 6666double diff = 0.0 ; 6667for (size_t i = 0 ; i < n ; i ++ ) { 6668ia [ i ] = (int32_t) a [ i ]; 6669ib [ i ] = (int32_t) b [ i ]; 6670diff += std:: fabs ( a [ i ] - ia [ i ]) + std:: fabs ( b [ i ] - ib [ i ]); 6671} 6672return diff + jdst ( ia . data (), ib . data (), n ); 6673} 6674}; 6675 6676enum MoeGatingFunc { 6677GATING_FUNC_SOFTMAX , 6678GATING_FUNC_SIGMOID , 6679GATING_FUNC_SOFTMAX_WEIGHT , 6680GATING_FUNC_SQRT_SOFTPLUS , 6681}; 6682 6683struct test_topk_moe : public test_case { 6684const std::array < int64_t, 4 > ne ; 6685const int n_expert_used ; 6686const bool with_norm ; 6687const bool bias_probs ; 6688const MoeGatingFunc gating_func ; 6689const float scale_w ; 6690ggml_tensor * weights {}; 6691ggml_tensor * selected_experts {}; 6692 6693test_topk_moe (std::array < int64_t, 4 > ne = { 10 , 5 , 1 , 1 }, 6694int n_expert_used = 1 , 6695bool with_norm = false, 6696bool bias_probs = false, 6697MoeGatingFunc gating_func = GATING_FUNC_SOFTMAX , 6698float scale_w = 0.0f ) : 6699ne ( ne ), 6700n_expert_used ( n_expert_used ), 6701with_norm ( with_norm ), 6702bias_probs ( bias_probs ), 6703gating_func ( gating_func ), 6704scale_w ( scale_w ) { 6705GGML_ASSERT ( n_expert_used <= ne [ 0 ]); 6706} 6707 6708std::string vars () override { return VARS_TO_STR6 ( ne , n_expert_used , with_norm , bias_probs , gating_func , scale_w ); } 6709 6710std::string op_desc (ggml_tensor * t ) override { 6711GGML_UNUSED ( t ); 6712return "TOPK_MOE" ; 6713} 6714 6715bool run_whole_graph () override { return true; } 6716 6717ggml_tensor * build_graph (ggml_context * ctx ) override { 6718const int n_expert = ne [ 0 ]; 6719const int n_tokens = ne [ 1 ]; 6720 6721ggml_tensor * logits = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne . data ()); 6722ggml_tensor * probs = 6723( gating_func == GATING_FUNC_SOFTMAX ) ? ggml_soft_max ( ctx , logits ) : 6724( gating_func == GATING_FUNC_SIGMOID ) ? ggml_sigmoid ( ctx , logits ) : 6725( gating_func == GATING_FUNC_SQRT_SOFTPLUS ) ? ggml_sqrt ( ctx , ggml_softplus ( ctx , logits )) : logits ; 6726ggml_set_name ( probs , "probs" ); 6727 6728ggml_tensor * selection_probs = probs ; 6729if ( bias_probs ) { 6730ggml_tensor * exp_probs_b = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , ne [ 0 ]); 6731ggml_set_name ( exp_probs_b , "exp_probs_b" ); 6732selection_probs = ggml_add ( ctx , probs , exp_probs_b ); 6733ggml_set_name ( selection_probs , "selection_probs" ); 6734} 6735 6736selected_experts = ggml_argsort_top_k ( ctx , selection_probs , n_expert_used ); // [n_expert_used, n_tokens] 6737ggml_set_name ( selected_experts , "selected_experts" ); 6738 6739weights = ggml_get_rows ( ctx , ggml_reshape_3d ( ctx , probs , 1 , n_expert , n_tokens ), selected_experts ); // [1, n_expert_used, n_tokens] 6740ggml_set_name ( weights , "weights" ); 6741 6742if ( gating_func == GATING_FUNC_SOFTMAX_WEIGHT ) { 6743weights = ggml_reshape_2d ( ctx , weights , n_expert_used , n_tokens ); 6744weights = ggml_soft_max ( ctx , weights ); // [n_expert_used, n_tokens] 6745weights = ggml_reshape_3d ( ctx , weights , 1 , n_expert_used , n_tokens ); 6746} 6747 6748if ( with_norm ) { 6749weights = ggml_reshape_2d ( ctx , weights , n_expert_used , n_tokens ); 6750ggml_tensor * weights_sum = ggml_sum_rows ( ctx , weights ); // [1, n_tokens] 6751ggml_set_name ( weights_sum , "weights_sum" ); 6752 6753weights_sum = ggml_clamp ( ctx , weights_sum , 6.103515625e-5 , INFINITY ); 6754weights = ggml_div ( ctx , weights , weights_sum ); // [n_expert_used, n_tokens] 6755weights = ggml_reshape_3d ( ctx , weights , 1 , n_expert_used , n_tokens ); 6756} 6757 6758if ( scale_w ) { 6759weights = ggml_scale ( ctx , weights , scale_w ); 6760} 6761 6762ggml_set_name ( weights , "weights" ); 6763return weights ; 6764} 6765// Verify two outputs 6766std::vector < ggml_tensor *> fusion_test_nodes () override { return { selected_experts , weights }; } 6767 6768// allow output in arbitrary order 6769double err ( const float * a , const float * b , size_t n ) override { 6770std::vector < float > a2 (n); 6771std::vector < float > b2 (n); 6772for (size_t i = 0 ; i < n ; ++ i ) { 6773a2 [ i ] = a [ i ]; 6774b2 [ i ] = b [ i ]; 6775} 6776std:: sort ( a2 . begin (), a2 . end ()); 6777std:: sort ( b2 . begin (), b2 . end ()); 6778return nmse ( a2 . data (), b2 . data (), n ); 6779} 6780}; 6781 6782struct test_moe_weighted_reduction : public test_case { 6783const int64_t n_embd ; 6784const int64_t n_expert_used ; 6785const int64_t n_tokens ; 6786const bool unaligned_experts ; 6787const bool with_expert_scale ; 6788const bool interleaved_views_adds ; 6789 6790test_moe_weighted_reduction ( 6791int64_t n_embd , int64_t n_expert_used , int64_t n_tokens , 6792bool unaligned_experts = false, bool with_expert_scale = false, bool interleaved_views_adds = false) : 6793n_embd ( n_embd ), n_expert_used ( n_expert_used ), n_tokens ( n_tokens ), 6794unaligned_experts ( unaligned_experts ), with_expert_scale ( with_expert_scale ), 6795interleaved_views_adds ( interleaved_views_adds ) {} 6796 6797std::string vars () override { 6798return VARS_TO_STR6 ( n_embd , n_expert_used , n_tokens , unaligned_experts , with_expert_scale , interleaved_views_adds ); 6799} 6800 6801std::string op_desc (ggml_tensor * t ) override { 6802GGML_UNUSED ( t ); 6803return "MOE_WEIGHTED_REDUCTION" ; 6804} 6805 6806bool run_whole_graph () override { return true; } 6807 6808ggml_tensor * build_graph (ggml_context * ctx ) override { 6809ggml_tensor * experts ; 6810if ( unaligned_experts ) { 6811ggml_tensor * storage = ggml_new_tensor_1d ( 6812ctx , GGML_TYPE_F32 , n_embd * n_expert_used * n_tokens + 1 ); 6813ggml_set_name ( storage , "experts_storage" ); 6814experts = ggml_view_3d ( ctx , storage , n_embd , n_expert_used , n_tokens , 6815n_embd * sizeof (float), n_embd * n_expert_used * sizeof (float), sizeof (float)); 6816} else { 6817experts = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , n_embd , n_expert_used , n_tokens ); 6818} 6819ggml_set_name ( experts , "experts" ); 6820ggml_tensor * weights = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , 1 , n_expert_used , n_tokens ); 6821ggml_set_name ( weights , "weights" ); 6822 6823ggml_tensor * scaled = experts ; 6824if ( with_expert_scale ) { 6825ggml_tensor * expert_scale = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , 1 , n_expert_used , n_tokens ); 6826ggml_set_name ( expert_scale , "expert_scale" ); 6827scaled = ggml_mul ( ctx , experts , expert_scale ); 6828ggml_set_name ( scaled , "scaled_experts" ); 6829} 6830 6831ggml_tensor * weighted = ggml_mul ( ctx , scaled , weights ); 6832ggml_set_name ( weighted , "weighted_experts" ); 6833 6834std::vector < ggml_tensor *> views (n_expert_used); 6835for (int64_t expert = 0 ; expert < n_expert_used ; ++ expert ) { 6836views [ expert ] = ggml_view_2d ( 6837ctx , weighted , n_embd , n_tokens , weighted -> nb [ 2 ], expert * weighted -> nb [ 1 ]); 6838if (! interleaved_views_adds && mode == MODE_TEST ) { 6839ggml_build_forward_expand ( gf , views [ expert ]); 6840} 6841} 6842 6843ggml_tensor * out = views [ 0 ]; 6844for (int64_t expert = 1 ; expert < n_expert_used ; ++ expert ) { 6845out = ggml_add ( ctx , out , views [ expert ]); 6846if (! interleaved_views_adds && mode == MODE_TEST ) { 6847ggml_build_forward_expand ( gf , out ); 6848} 6849} 6850ggml_set_name ( out , "moe_weighted_reduction" ); 6851return out ; 6852} 6853}; 6854 6855struct test_mul_mat_vec_fusion : public test_case { 6856const ggml_type type ; 6857const ggml_glu_op glu_op ; 6858const int64_t m ; 6859const int64_t n ; 6860const int64_t k ; 6861const bool use_id ; 6862const int n_mats ; 6863const int n_used ; 6864const bool b ; // broadcast b matrix (only for use_id) 6865const bool with_bias ; 6866const bool with_gate ; 6867const bool with_lane_scale ; 6868std::array < int64_t, 2 > batch_dims ; 6869 6870test_mul_mat_vec_fusion (ggml_type type , ggml_glu_op op , int64_t m , int64_t n , int64_t k , 6871bool use_id = false, int n_mats = 1 , int n_used = 1 , bool b = false, bool with_bias = false, bool with_gate = true, 6872bool with_lane_scale = false, std::array < int64_t, 2 > batch_dims = { 4 , 2 }) 6873: type ( type ), glu_op ( op ), m ( m ), n ( n ), k ( k ), use_id ( use_id ), n_mats ( n_mats ), n_used ( n_used ), b ( b ), with_bias ( with_bias ), 6874with_gate ( with_gate ), with_lane_scale ( with_lane_scale ), batch_dims ( batch_dims ) { 6875if ( use_id ) { 6876GGML_ASSERT ( n_used <= n_mats ); 6877} 6878} 6879 6880std::string vars () override { 6881return VARS_TO_STR13 ( type , glu_op , m , n , k , use_id , n_mats , n_used , b , with_bias , with_gate , with_lane_scale , batch_dims ); 6882} 6883 6884std::string op_desc (ggml_tensor * t ) override { 6885GGML_UNUSED ( t ); 6886return "MUL_MAT_VEC_FUSION" ; 6887} 6888 6889bool run_whole_graph () override { return true; } 6890bool use_weight_context () override { return use_id && with_lane_scale ; } 6891 6892ggml_tensor * build_gate (ggml_context * ctx , ggml_tensor * ffn_gate , ggml_tensor * ffn_up ) { 6893ggml_tensor * out = nullptr ; 6894if ( with_gate ) { 6895if ( glu_op == GGML_GLU_OP_SWIGLU_OAI ) { 6896constexpr float alpha = 1.702f ; 6897constexpr float limit = 7.0f ; 6898out = ggml_swiglu_oai ( ctx , ffn_gate , ffn_up , alpha , limit ); 6899} else if ( glu_op == GGML_GLU_OP_SWIGLU_CLAMP ) { 6900constexpr float limit = 10.0f ; 6901out = ggml_swiglu_clamp ( ctx , ffn_gate , ffn_up , limit ); 6902} else { 6903out = ggml_glu_split ( ctx , ffn_gate , ffn_up , glu_op ); 6904} 6905} 6906return out ; 6907} 6908 6909ggml_tensor * build_lane_scale_dense (ggml_context * ctx , ggml_tensor * out ) { 6910ggml_tensor * scale = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , 1 ); 6911return ggml_mul ( ctx , out , scale ); 6912} 6913 6914ggml_tensor * build_lane_scale_id (ggml_context * ctx , ggml_context * ctx_weights , ggml_tensor * out , ggml_tensor * ids ) { 6915GGML_ASSERT ( ctx_weights ); 6916ggml_tensor * scale = ggml_new_tensor_1d ( ctx_weights , GGML_TYPE_F32 , n_mats ); 6917ggml_tensor * s = ggml_reshape_3d ( ctx , scale , 1 , n_mats , 1 ); 6918s = ggml_repeat_4d ( ctx , s , 1 , n_mats , m , 1 ); 6919s = ggml_get_rows ( ctx , s , ids ); 6920return ggml_mul ( ctx , out , s ); 6921} 6922 6923ggml_tensor * build_graph (ggml_context * ctx ) override { 6924GGML_ASSERT (! use_weight_context ()); 6925return build_graph ( ctx , nullptr ); 6926} 6927 6928ggml_tensor * build_graph (ggml_context * ctx , ggml_context * ctx_weights ) override { 6929if (! use_id ) { 6930const int channels = batch_dims [ 0 ]; 6931const int samples = batch_dims [ 1 ]; 6932std::array < int64_t, 4 > ne = { k , m , channels , samples }; 6933std::array < int64_t, 4 > ne0 = { k , n , channels , samples }; 6934 6935ggml_tensor * cur = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne . data ()); 6936ggml_tensor * gate = with_gate ? ggml_new_tensor ( ctx , type , 4 , ne0 . data ()) : nullptr ; 6937ggml_tensor * up = ggml_new_tensor ( ctx , type , 4 , ne0 . data ()); 6938 6939auto build_lane_up = [ & ]() { 6940ggml_tensor * ffn_up = ggml_mul_mat ( ctx , up , cur ); 6941if ( with_lane_scale ) { 6942ffn_up = build_lane_scale_dense ( ctx , ffn_up ); 6943} 6944if ( with_bias ) { 6945std::array < int64_t, 4 > bias_ne = { ffn_up -> ne [ 0 ], 1 , channels , samples }; 6946ggml_tensor * up_bias = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , bias_ne . data ()); 6947ffn_up = ggml_add ( ctx , ffn_up , up_bias ); 6948} 6949return ffn_up ; 6950}; 6951 6952auto build_lane_gate = [ & ]() { 6953ggml_tensor * ffn_gate = ggml_mul_mat ( ctx , gate , cur ); 6954if ( with_lane_scale ) { 6955ffn_gate = build_lane_scale_dense ( ctx , ffn_gate ); 6956} 6957if ( with_bias ) { 6958std::array < int64_t, 4 > bias_ne = { ffn_gate -> ne [ 0 ], 1 , channels , samples }; 6959ggml_tensor * gate_bias = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , bias_ne . data ()); 6960ffn_gate = ggml_add ( ctx , ffn_gate , gate_bias ); 6961} 6962return ffn_gate ; 6963}; 6964 6965ggml_tensor * ffn_up = build_lane_up (); 6966ggml_tensor * ffn_gate = with_gate ? build_lane_gate () : nullptr ; 6967 6968ggml_tensor * out = with_gate ? build_gate ( ctx , ffn_gate , ffn_up ) : ffn_up ; 6969 6970std::array < int64_t, 4 > bias2_ne = { out -> ne [ 0 ], 1 , channels , samples }; 6971ggml_tensor * bias2 = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , bias2_ne . data ()); 6972out = ggml_add ( ctx , out , bias2 ); 6973 6974ggml_set_name ( out , "out" ); 6975return out ; 6976} else { 6977ggml_tensor * gates = ggml_new_tensor_3d ( ctx , type , k , n , n_mats ); 6978ggml_tensor * ups = ggml_new_tensor_3d ( ctx , type , k , n , n_mats ); 6979ggml_tensor * ids = ggml_new_tensor_2d ( ctx , GGML_TYPE_I32 , n_mats , m ); 6980 6981if ( n_used != n_mats ) { 6982ids = ggml_view_2d ( ctx , ids , n_used , m , ids -> nb [ 1 ], 0 ); 6983} 6984 6985ggml_tensor * cur = ggml_new_tensor_3d ( ctx , GGML_TYPE_F32 , k , this -> b ? 1 : n_used , m ); 6986ggml_set_name ( cur , "cur" ); 6987 6988auto build_lane_up = [ & ]() { 6989ggml_tensor * ffn_up = ggml_mul_mat_id ( ctx , ups , cur , ids ); 6990if ( with_lane_scale ) { 6991ffn_up = build_lane_scale_id ( ctx , ctx_weights , ffn_up , ids ); 6992} 6993if ( with_bias ) { 6994ggml_tensor * up_bias_param = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , ffn_up -> ne [ 0 ], n_mats ); 6995ffn_up = ggml_add_id ( ctx , ffn_up , up_bias_param , ids ); 6996} 6997return ffn_up ; 6998}; 6999 7000auto build_lane_gate = [ & ]() { 7001ggml_tensor * ffn_gate = ggml_mul_mat_id ( ctx , gates , cur , ids ); 7002if ( with_lane_scale ) { 7003ffn_gate = build_lane_scale_id ( ctx , ctx_weights , ffn_gate , ids ); 7004} 7005if ( with_bias ) { 7006ggml_tensor * gate_bias_param = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , ffn_gate -> ne [ 0 ], n_mats ); 7007ffn_gate = ggml_add_id ( ctx , ffn_gate , gate_bias_param , ids ); 7008} 7009return ffn_gate ; 7010}; 7011 7012ggml_tensor * ffn_up = build_lane_up (); 7013ggml_tensor * ffn_gate = with_gate ? build_lane_gate () : nullptr ; 7014 7015ggml_tensor * out = with_gate ? build_gate ( ctx , ffn_gate , ffn_up ) : ffn_up ; 7016 7017std::array < int64_t, 4 > scale_ne { 1 , out -> ne [ 1 ], out -> ne [ 2 ], out -> ne [ 3 ] }; 7018ggml_tensor * scale = ggml_new_tensor ( ctx , out -> type , 4 , scale_ne . data ()); 7019out = ggml_mul ( ctx , out , scale ); 7020 7021ggml_set_name ( out , "out" ); 7022return out ; 7023} 7024} 7025 7026void initialize_tensors (ggml_context * ctx ) override { 7027if (! use_id ) { 7028for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7029init_tensor_uniform ( t ); 7030} 7031} else { 7032init_mul_mat_id_tensors ( ctx , n_mats ); 7033} 7034} 7035 7036double max_nmse_err () override { 7037return 5e-3 ; 7038} 7039}; 7040 7041// GGML_OP_SUM 7042struct test_sum : public test_case { 7043const ggml_type type ; 7044const std::array < int64_t, 4 > ne ; 7045const std::array < int64_t, 4 > permute ; 7046bool _use_permute ; 7047 7048std::string vars () override { 7049std::string v = VARS_TO_STR2 ( type , ne ); 7050if ( _use_permute ) v += "," + VAR_TO_STR ( permute ); 7051return v ; 7052} 7053 7054test_sum (ggml_type type = GGML_TYPE_F32 , 7055std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 7056std::array < int64_t, 4 > permute = { 0 , 0 , 0 , 0 }) 7057: type ( type ), ne ( ne ), permute ( permute ), 7058_use_permute ( permute [ 0 ] + permute [ 1 ] + permute [ 2 ] + permute [ 3 ] > 0 ) {} 7059 7060ggml_tensor * build_graph (ggml_context * ctx ) override { 7061ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7062ggml_set_param ( a ); 7063ggml_set_name ( a , "a" ); 7064 7065if ( _use_permute ) { 7066a = ggml_permute ( ctx , a , permute [ 0 ], permute [ 1 ], permute [ 2 ], permute [ 3 ]); 7067ggml_set_name ( a , "a_permuted" ); 7068} 7069 7070ggml_tensor * out = ggml_sum ( ctx , a ); 7071ggml_set_name ( out , "out" ); 7072 7073return out ; 7074} 7075 7076float grad_eps () override { 7077return 0.1f * sqrtf ( ne [ 0 ] * ne [ 1 ] * ne [ 2 ] * ne [ 3 ]); 7078} 7079 7080// Don't center the distribution around zero. Helps to avoid catastrophic cancellation. 7081void initialize_tensors (ggml_context * ctx ) override { 7082for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 7083init_tensor_uniform ( t , -0.9f , 1.1f ); 7084} 7085} 7086}; 7087 7088// GGML_OP_SUM_ROWS 7089struct test_sum_rows : public test_case { 7090const ggml_type type ; 7091const std::array < int64_t, 4 > ne ; 7092const bool permute ; 7093const bool slice ; 7094 7095std::string vars () override { 7096return VARS_TO_STR4 ( type , ne , permute , slice ); 7097} 7098 7099test_sum_rows (ggml_type type = GGML_TYPE_F32 , 7100std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }, 7101bool permute = false, bool slice = false) 7102: type ( type ), ne ( ne ), permute ( permute ), slice ( slice ) {} 7103 7104ggml_tensor * build_graph (ggml_context * ctx ) override { 7105ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7106ggml_set_param ( a ); 7107ggml_set_name ( a , "a" ); 7108 7109if ( slice ) { 7110a = ggml_view_4d ( ctx , a , 7111ne [ 0 ], ne [ 1 ], ne [ 2 ] / 2 , ne [ 3 ] - 1 , 7112a -> nb [ 1 ], a -> nb [ 2 ] * 2 , a -> nb [ 3 ], /*offset=*/ a -> nb [ 3 ]); 7113} 7114if ( permute ) { 7115a = ggml_permute ( ctx , a , 0 , 2 , 3 , 1 ); 7116} 7117 7118ggml_tensor * out = ggml_sum_rows ( ctx , a ); 7119ggml_set_name ( out , "out" ); 7120 7121return out ; 7122} 7123}; 7124 7125// GGML_OP_MEAN 7126struct test_mean : public test_case { 7127const ggml_type type ; 7128const std::array < int64_t, 4 > ne ; 7129 7130std::string vars () override { 7131return VARS_TO_STR2 ( type , ne ); 7132} 7133 7134test_mean (ggml_type type = GGML_TYPE_F32 , 7135std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7136: type ( type ), ne ( ne ) {} 7137 7138ggml_tensor * build_graph (ggml_context * ctx ) override { 7139ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7140ggml_set_param ( a ); 7141ggml_set_name ( a , "a" ); 7142 7143ggml_tensor * out = ggml_mean ( ctx , a ); 7144ggml_set_name ( out , "out" ); 7145 7146return out ; 7147} 7148 7149float grad_eps () override { 7150return 0.1f * ne [ 0 ] * ne [ 1 ] * ne [ 2 ] * ne [ 3 ]; 7151} 7152 7153// Don't center the distribution around zero. Helps to avoid catastrophic cancellation. 7154void initialize_tensors (ggml_context * ctx ) override { 7155for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != nullptr ; t = ggml_get_next_tensor ( ctx , t )) { 7156init_tensor_uniform ( t , -0.9f , 1.1f ); 7157} 7158} 7159}; 7160 7161// GGML_OP_UPSCALE 7162struct test_upscale : public test_case { 7163const ggml_type type ; 7164const std::array < int64_t, 4 > ne ; 7165const int32_t scale_factor ; 7166const bool transpose ; 7167const ggml_scale_mode mode ; 7168 7169std::string vars () override { 7170return VARS_TO_STR5 ( type , ne , scale_factor , mode , transpose ); 7171} 7172 7173test_upscale (ggml_type type = GGML_TYPE_F32 , 7174std::array < int64_t, 4 > ne = { 512 , 512 , 3 , 1 }, 7175int32_t scale_factor = 2 , ggml_scale_mode mode = GGML_SCALE_MODE_NEAREST , bool transpose = false) 7176: type ( type ), ne ( ne ), scale_factor ( scale_factor ), transpose ( transpose ), mode ( mode ) {} 7177 7178ggml_tensor * build_graph (ggml_context * ctx ) override { 7179ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7180ggml_set_name ( a , "a" ); 7181 7182if ( transpose ) { 7183a = ggml_transpose ( ctx , a ); 7184ggml_set_name ( a , "a_transposed" ); 7185} 7186 7187ggml_tensor * out = ggml_upscale ( ctx , a , scale_factor , mode ); 7188ggml_set_name ( out , "out" ); 7189 7190return out ; 7191} 7192}; 7193 7194// GGML_OP_UPSCALE (via ggml_interpolate) 7195struct test_interpolate : public test_case { 7196const ggml_type type ; 7197const std::array < int64_t, 4 > ne ; 7198const std::array < int64_t, 4 > ne_tgt ; 7199const ggml_scale_mode mode = GGML_SCALE_MODE_NEAREST ; 7200 7201std::string vars () override { 7202return VARS_TO_STR4 ( type , ne , ne_tgt , mode ); 7203} 7204 7205test_interpolate (ggml_type type = GGML_TYPE_F32 , 7206std::array < int64_t, 4 > ne = { 2 , 5 , 7 , 11 }, 7207std::array < int64_t, 4 > ne_tgt = { 5 , 7 , 11 , 13 }, 7208ggml_scale_mode mode = GGML_SCALE_MODE_NEAREST ) 7209: type ( type ), ne ( ne ), ne_tgt ( ne_tgt ), mode ( mode ) {} 7210 7211ggml_tensor * build_graph (ggml_context * ctx ) override { 7212ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7213ggml_set_name ( a , "a" ); 7214 7215ggml_tensor * out = ggml_interpolate ( ctx , a , ne_tgt [ 0 ], ne_tgt [ 1 ], ne_tgt [ 2 ], ne_tgt [ 3 ], mode ); 7216ggml_set_name ( out , "out" ); 7217 7218return out ; 7219} 7220}; 7221 7222// GGML_OP_GROUP_NORM 7223struct test_group_norm : public test_case { 7224const ggml_type type ; 7225const std::array < int64_t, 4 > ne ; 7226const int32_t num_groups ; 7227const float eps ; 7228 7229std::string vars () override { 7230return VARS_TO_STR4 ( type , ne , num_groups , eps ); 7231} 7232 7233test_group_norm (ggml_type type = GGML_TYPE_F32 , 7234std::array < int64_t, 4 > ne = { 64 , 64 , 320 , 1 }, 7235int32_t num_groups = 32 , 7236float eps = 1e-6f ) 7237: type ( type ), ne ( ne ), num_groups ( num_groups ), eps ( eps ) {} 7238 7239ggml_tensor * build_graph (ggml_context * ctx ) override { 7240ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7241ggml_set_name ( a , "a" ); 7242 7243ggml_tensor * out = ggml_group_norm ( ctx , a , num_groups , eps ); 7244ggml_set_name ( out , "out" ); 7245 7246return out ; 7247} 7248}; 7249 7250// GGML_OP_GROUP_NORM + GGML_OP_MUL + GGML_OP_ADD 7251struct test_group_norm_mul_add : public test_case { 7252const ggml_type type ; 7253const std::array < int64_t, 4 > ne ; 7254int num_groups ; 7255float eps ; 7256 7257std::string op_desc (ggml_tensor * t ) override { 7258GGML_UNUSED ( t ); 7259return "GROUP_NORM_MUL_ADD" ; 7260} 7261 7262bool run_whole_graph () override { return true; } 7263 7264std::string vars () override { 7265return VARS_TO_STR4 ( type , ne , num_groups , eps ); 7266} 7267 7268test_group_norm_mul_add (ggml_type type = GGML_TYPE_F32 , 7269std::array < int64_t, 4 > ne = { 128 , 1 , 1 , 1 }, 7270int num_groups = 4 , 7271float eps = 1e-5f ) 7272: type ( type ), ne ( ne ), num_groups ( num_groups ), eps ( eps ) {} 7273 7274ggml_tensor * build_graph (ggml_context * ctx ) override { 7275ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7276ggml_tensor * w = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7277ggml_tensor * b = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7278ggml_set_param ( a ); ggml_set_param ( w ); ggml_set_param ( b ); 7279ggml_set_name ( a , "a" ); ggml_set_name ( w , "w" ); ggml_set_name ( b , "b" ); 7280ggml_tensor * n = ggml_group_norm ( ctx , a , num_groups , eps ); 7281ggml_tensor * m = ggml_mul ( ctx , n , w ); 7282ggml_tensor * out = ggml_add ( ctx , m , b ); 7283ggml_set_name ( out , "out" ); 7284return out ; 7285} 7286}; 7287 7288// GGML_OP_L2_NORM x N: independent same-shape norms in one graph (strided qkv views or 7289// contiguous), consuming adds nested so the norms stay adjacent in the graph. 7290struct test_l2_norm_batch : public test_case { 7291const ggml_type type ; 7292const std::array < int64_t, 4 > ne ; 7293const int n_norms ; 7294const float eps ; 7295const bool strided ; 7296 7297std::string vars () override { return VARS_TO_STR5 ( type , ne , n_norms , eps , strided ); } 7298std::string op_desc (ggml_tensor * t ) override { GGML_UNUSED ( t ); return "L2_NORM_BATCH" ; } 7299bool run_whole_graph () override { return true; } 7300 7301test_l2_norm_batch (ggml_type type = GGML_TYPE_F32 , std::array < int64_t, 4 > ne = { 128 , 16 , 16 , 1 }, 7302int n_norms = 4 , float eps = 1e-12f , bool strided = true) 7303: type ( type ), ne ( ne ), n_norms ( n_norms ), eps ( eps ), strided ( strided ) {} 7304 7305ggml_tensor * build_graph (ggml_context * ctx ) override { 7306GGML_ASSERT ( n_norms >= 2 && n_norms <= 8 ); 7307ggml_tensor * parent = nullptr ; 7308if ( strided ) { 7309parent = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ] * n_norms , ne [ 2 ], ne [ 3 ]); // qkv buffer 7310} 7311ggml_tensor * norms [ 8 ] = {}; 7312for (int t = 0 ; t < n_norms ; ++ t ) { 7313ggml_tensor * src ; 7314if ( strided ) { 7315src = ggml_view_4d ( ctx , parent , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ], parent -> nb [ 1 ], parent -> nb [ 2 ], 7316parent -> nb [ 3 ], t * ne [ 1 ] * parent -> nb [ 1 ]); 7317} else { 7318src = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7319} 7320norms [ t ] = ggml_l2_norm ( ctx , src , eps ); 7321} 7322ggml_tensor * out = norms [ n_norms - 1 ]; 7323for (int t = n_norms - 2 ; t >= 0 ; -- t ) { 7324out = ggml_add ( ctx , norms [ t ], out ); 7325} 7326ggml_set_name ( out , "out" ); 7327return out ; 7328} 7329}; 7330 7331// GGML_OP_L2_NORM 7332struct test_l2_norm : public test_case { 7333const ggml_type type ; 7334const std::array < int64_t, 4 > ne ; 7335const float eps ; 7336bool v ; 7337bool noncontig_rows ; 7338 7339std::string vars () override { 7340return VARS_TO_STR5 ( type , ne , eps , v , noncontig_rows ); 7341} 7342 7343test_l2_norm (ggml_type type = GGML_TYPE_F32 , 7344std::array < int64_t, 4 > ne = { 64 , 64 , 320 , 1 }, 7345float eps = 1e-12f , 7346bool v = false, 7347bool noncontig_rows = false) 7348: type ( type ), ne ( ne ), eps ( eps ), v ( v ), noncontig_rows ( noncontig_rows ) {} 7349 7350ggml_tensor * build_graph (ggml_context * ctx ) override { 7351const std::array < int64_t, 4 > ne_a = noncontig_rows ? 7352std::array < int64_t, 4 > { ne [ 1 ], ne [ 0 ], ne [ 2 ], ne [ 3 ] } : ne ; 7353ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7354ggml_set_name ( a , "a" ); 7355 7356if ( noncontig_rows ) { 7357a = ggml_permute ( ctx , a , 1 , 0 , 2 , 3 ); 7358ggml_set_name ( a , "permuted a" ); 7359} 7360if ( v ) { 7361a = ggml_view_4d ( ctx , a , a -> ne [ 0 ]/ 2 , a -> ne [ 1 ]/ 2 , a -> ne [ 2 ]/ 2 , a -> ne [ 3 ]/ 2 , a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 7362ggml_set_name ( a , "view of a" ); 7363} 7364 7365ggml_tensor * out = ggml_l2_norm ( ctx , a , eps ); 7366ggml_set_name ( out , "out" ); 7367 7368return out ; 7369} 7370}; 7371 7372// GGML_OP_ACC 7373struct test_acc : public test_case { 7374const ggml_type type ; 7375const std::array < int64_t, 4 > ne_a ; 7376const std::array < int64_t, 4 > ne_b ; 7377const int64_t stride_dim ; 7378 7379std::string vars () override { 7380return VARS_TO_STR4 ( type , ne_a , ne_b , stride_dim ); 7381} 7382 7383test_acc (ggml_type type = GGML_TYPE_F32 , 7384std::array < int64_t, 4 > ne_a = { 256 , 17 , 2 , 3 }, 7385std::array < int64_t, 4 > ne_b = { 256 , 16 , 2 , 3 }, 7386uint64_t stride_dim = -1 ) 7387: type ( type ), ne_a ( ne_a ), ne_b ( ne_b ), stride_dim ( stride_dim ) {} 7388 7389ggml_tensor * build_graph (ggml_context * ctx ) override { 7390ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7391ggml_set_param ( a ); 7392ggml_set_name ( a , "a" ); 7393 7394ggml_tensor * b ; 7395if ( stride_dim == 1 || stride_dim == 2 || stride_dim == 3 ) { 7396// Create a larger tensor and take a view at a non-zero offset. 7397// This tests that the backend correctly handles b's data offset 7398std::array < int64_t, 4 > ne_b_pad = { ne_b [ 0 ], ne_b [ 1 ], ne_b [ 2 ], ne_b [ 3 ]}; 7399ne_b_pad [ stride_dim ] += 1 ; 7400ggml_tensor * b_pad = ggml_new_tensor ( ctx , type , 4 , ne_b_pad . data ()); 7401ggml_set_param ( b_pad ); 7402ggml_set_name ( b_pad , "b_pad" ); 7403// View that skips the first row, so b has a non-zero byte offset 7404b = ggml_view_4d ( ctx , b_pad , 7405ne_b [ 0 ], ne_b [ 1 ], ne_b [ 2 ], ne_b [ 3 ], 7406b_pad -> nb [ 1 ], b_pad -> nb [ 2 ], b_pad -> nb [ 3 ], 7407b_pad -> nb [ 1 ]); 7408} else { 7409b = ggml_new_tensor ( ctx , type , 4 , ne_b . data ()); 7410ggml_set_param ( b ); 7411} 7412ggml_set_name ( b , "b" ); 7413 7414// When ne_b[0] < ne_a[0], a->nb[1] != b->nb[1], so the stride 7415// parameters to ggml_acc don't match b's natural stride. 7416ggml_tensor * out = ggml_acc ( ctx , a , b , a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 7417ggml_set_name ( out , "out" ); 7418 7419return out ; 7420} 7421}; 7422 7423// GGML_OP_PAD 7424struct test_pad : public test_case { 7425const ggml_type type ; 7426const std::array < int64_t, 4 > ne_a ; 7427const int pad_0 ; 7428const int pad_1 ; 7429const bool circular ; 7430 7431std::string vars () override { 7432return VARS_TO_STR5 ( type , ne_a , pad_0 , pad_1 , circular ); 7433} 7434 7435test_pad (ggml_type type = GGML_TYPE_F32 , 7436std::array < int64_t, 4 > ne_a = { 512 , 512 , 1 , 1 }, 7437int pad_0 = 1 , int pad_1 = 1 , bool circular = false) 7438: type ( type ), ne_a ( ne_a ), pad_0 ( pad_0 ), pad_1 ( pad_1 ), circular ( circular ) {} 7439 7440ggml_tensor * build_graph (ggml_context * ctx ) override { 7441ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7442ggml_set_name ( a , "a" ); 7443 7444ggml_tensor * out = circular 7445? ggml_pad_circular ( ctx , a , pad_0 , pad_1 , 0 , 0 ) 7446: ggml_pad ( ctx , a , pad_0 , pad_1 , 0 , 0 ); 7447ggml_set_name ( out , "out" ); 7448 7449return out ; 7450} 7451}; 7452 7453// GGML_OP_PAD (with extension) 7454struct test_pad_ext : public test_case { 7455const ggml_type type ; 7456const std::array < int64_t, 4 > ne_a ; 7457const int lp0 ; 7458const int rp0 ; 7459const int lp1 ; 7460const int rp1 ; 7461const int lp2 ; 7462const int rp2 ; 7463const int lp3 ; 7464const int rp3 ; 7465const int tfrm ; // 0 - none, 1 - non-cont, 2 - perm 7466const bool circular ; 7467 7468std::string vars () override { 7469return VARS_TO_STR12 ( type , ne_a , lp0 , rp0 , lp1 , rp1 , lp2 , rp2 , lp3 , rp3 , tfrm , circular ); 7470} 7471 7472test_pad_ext (ggml_type type = GGML_TYPE_F32 , 7473std::array < int64_t, 4 > ne_a = { 512 , 512 , 3 , 1 }, 7474int lp0 = 1 , int rp0 = 1 , int lp1 = 1 , int rp1 = 1 , 7475int lp2 = 1 , int rp2 = 1 , int lp3 = 1 , int rp3 = 1 , 7476int tfrm = 0 , bool circular = false) 7477: type ( type ), ne_a ( ne_a ), lp0 ( lp0 ), rp0 ( rp0 ), lp1 ( lp1 ), rp1 ( rp1 ), lp2 ( lp2 ), rp2 ( rp2 ), lp3 ( lp3 ), rp3 ( rp3 ), 7478tfrm ( tfrm ), circular ( circular ) {} 7479 7480ggml_tensor * build_graph (ggml_context * ctx ) override { 7481ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7482ggml_set_name ( a , "a" ); 7483 7484if ( tfrm == 1 ) { 7485a = ggml_view_4d ( ctx , a , ( a -> ne [ 0 ] + 1 ) / 2 , ( a -> ne [ 1 ] + 1 ) / 2 , ( a -> ne [ 2 ] + 1 ) / 2 , ( a -> ne [ 3 ] + 1 ) / 2 , a -> nb [ 1 ], a -> nb [ 2 ], a -> nb [ 3 ], 0 ); 7486ggml_set_name ( a , "view of a" ); 7487} else if ( tfrm == 2 ) { 7488a = ggml_permute ( ctx , a , 2 , 1 , 0 , 3 ); 7489ggml_set_name ( a , "permuted a" ); 7490} 7491 7492ggml_tensor * out = circular 7493? ggml_pad_ext_circular ( ctx , a , lp0 , rp0 , lp1 , rp1 , lp2 , rp2 , lp3 , rp3 ) 7494: ggml_pad_ext ( ctx , a , lp0 , rp0 , lp1 , rp1 , lp2 , rp2 , lp3 , rp3 ); 7495ggml_set_name ( out , "out" ); 7496 7497return out ; 7498} 7499}; 7500 7501// GGML_OP_PAD_REFLECT_1D 7502struct test_pad_reflect_1d : public test_case { 7503const ggml_type type ; 7504const std::array < int64_t, 4 > ne_a ; 7505const int pad_0 ; 7506const int pad_1 ; 7507 7508std::string vars () override { 7509return VARS_TO_STR4 ( type , ne_a , pad_0 , pad_1 ); 7510} 7511 7512test_pad_reflect_1d (ggml_type type = GGML_TYPE_F32 , 7513std::array < int64_t, 4 > ne_a = { 512 , 34 , 2 , 1 }, 7514int pad_0 = 10 , int pad_1 = 9 ) 7515: type ( type ), ne_a ( ne_a ), pad_0 ( pad_0 ), pad_1 ( pad_1 ) {} 7516 7517ggml_tensor * build_graph (ggml_context * ctx ) override { 7518ggml_tensor * a = ggml_new_tensor ( ctx , type , 2 , ne_a . data ()); 7519ggml_set_name ( a , "a" ); 7520 7521ggml_tensor * out = ggml_pad_reflect_1d ( ctx , a , pad_0 , pad_1 ); 7522ggml_set_name ( out , "out" ); 7523 7524return out ; 7525} 7526}; 7527 7528// GGML_OP_ROLL 7529struct test_roll : public test_case { 7530const int shift0 ; 7531const int shift1 ; 7532const int shift3 ; 7533const int shift4 ; 7534const bool permute ; 7535 7536std::string vars () override { 7537return VARS_TO_STR5 ( shift0 , shift1 , shift3 , shift4 , permute ); 7538} 7539 7540test_roll (int shift0 = 3 , int shift1 = -2 , int shift3 = 1 , int shift4 = -1 , bool permute = false) 7541: shift0 ( shift0 ), shift1 ( shift1 ), shift3 ( shift3 ), shift4 ( shift4 ), permute ( permute ) {} 7542 7543ggml_tensor * build_graph (ggml_context * ctx ) override { 7544int64_t ne [ 4 ] = { 10 , 5 , 4 , 3 }; 7545ggml_tensor * a = ggml_new_tensor ( ctx , GGML_TYPE_F32 , 4 , ne ); 7546ggml_set_name ( a , "a" ); 7547 7548if ( permute ) { 7549// ggml_roll only requires nb[0] == type size, so a permuted src is valid 7550a = ggml_permute ( ctx , a , 0 , 2 , 1 , 3 ); 7551ggml_set_name ( a , "a_permuted" ); 7552} 7553 7554ggml_tensor * out = ggml_roll ( ctx , a , shift0 , shift1 , shift3 , shift4 ); 7555ggml_set_name ( out , "out" ); 7556 7557return out ; 7558} 7559}; 7560 7561// GGML_OP_ARANGE 7562struct test_arange : public test_case { 7563const ggml_type type ; 7564const float start ; 7565const float stop ; 7566const float step ; 7567 7568std::string vars () override { 7569return VARS_TO_STR4 ( type , start , stop , step ); 7570} 7571 7572test_arange (ggml_type type = GGML_TYPE_F32 , 7573float start = 0.f , float stop = 10.f , float step = 1.f ) 7574: type ( type ), start ( start ), stop ( stop ), step ( step ) {} 7575 7576ggml_tensor * build_graph (ggml_context * ctx ) override { 7577ggml_tensor * out = ggml_arange ( ctx , start , stop , step ); 7578ggml_set_name ( out , "out" ); 7579 7580return out ; 7581} 7582}; 7583 7584// GGML_OP_TIMESTEP_EMBEDDING 7585struct test_timestep_embedding : public test_case { 7586const ggml_type type ; 7587const std::array < int64_t, 4 > ne_a ; 7588const int dim ; 7589const int max_period ; 7590 7591std::string vars () override { 7592return VARS_TO_STR4 ( type , ne_a , dim , max_period ); 7593} 7594 7595test_timestep_embedding (ggml_type type = GGML_TYPE_F32 , 7596std::array < int64_t, 4 > ne_a = { 2 , 1 , 1 , 1 }, 7597int dim = 320 , int max_period = 10000 ) 7598: type ( type ), ne_a ( ne_a ), dim ( dim ), max_period ( max_period ) {} 7599 7600ggml_tensor * build_graph (ggml_context * ctx ) override { 7601ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7602ggml_set_name ( a , "a" ); 7603 7604ggml_tensor * out = ggml_timestep_embedding ( ctx , a , dim , max_period ); 7605ggml_set_name ( out , "out" ); 7606 7607return out ; 7608} 7609}; 7610 7611// GGML_OP_LEAKY_RELU 7612struct test_leaky_relu : public test_case { 7613const ggml_type type ; 7614const std::array < int64_t, 4 > ne_a ; 7615const float negative_slope ; 7616 7617std::string vars () override { 7618return VARS_TO_STR3 ( type , ne_a , negative_slope ); 7619} 7620 7621test_leaky_relu (ggml_type type = GGML_TYPE_F32 , 7622std::array < int64_t, 4 > ne_a = { 10 , 5 , 4 , 3 }, 7623float negative_slope = 0.1f ) 7624: type ( type ), ne_a ( ne_a ), negative_slope ( negative_slope ) {} 7625 7626ggml_tensor * build_graph (ggml_context * ctx ) override { 7627ggml_tensor * a = ggml_new_tensor ( ctx , type , 4 , ne_a . data ()); 7628ggml_set_name ( a , "a" ); 7629 7630ggml_tensor * out = ggml_leaky_relu ( ctx , a , negative_slope , true); 7631ggml_set_name ( out , "out" ); 7632 7633return out ; 7634} 7635}; 7636 7637// GGML_OP_FLASH_ATTN_EXT 7638struct test_flash_attn_ext : public test_case { 7639const int64_t hsk ; // K head size 7640const int64_t hsv ; // V head size 7641const int64_t nh ; // num heads 7642const std::array < int64_t, 2 > nr23 ; // repeat in dim 2 and 3, tests for grouped-query attention 7643const int64_t kv ; // kv size 7644const int64_t nb ; // batch size 7645 7646const bool mask ; // use mask 7647const bool sinks ; // use sinks 7648 7649const float max_bias ; // ALiBi 7650const float logit_softcap ; // Gemma 2 7651 7652const ggml_prec prec ; 7653const ggml_type type_K ; 7654const ggml_type type_V ; 7655std::array < int32_t, 4 > permute ; 7656const bool kv_view ; // create K/V as views of a larger buffer (like a KV cache) 7657const bool v_is_view_of_k ; 7658const int64_t n_kv_max ; 7659 7660std::string vars () override { 7661return VARS_TO_STR17 ( hsk , hsv , nh , nr23 , kv , nb , mask , sinks , max_bias , logit_softcap , prec , type_K , type_V , permute , kv_view , v_is_view_of_k , n_kv_max ); 7662} 7663 7664double max_nmse_err () override { 7665return 5e-4 ; 7666} 7667 7668uint64_t op_flops (ggml_tensor * t ) override { 7669GGML_UNUSED ( t ); 7670// Just counting matmul costs: 7671// Q*K^T is nb x hsk x kv, P*V is nb x kv x hsv, per head 7672return ( 2 * nh * nr23 [ 0 ] * nb * ( hsk + hsv ) * kv ) * nr23 [ 1 ]; 7673} 7674 7675test_flash_attn_ext (int64_t hsk = 128 , int64_t hsv = 128 , int64_t nh = 32 , std::array < int64_t, 2 > nr23 = { 1 , 1 }, int64_t kv = 96 , int64_t nb = 8 , 7676bool mask = true, bool sinks = false, float max_bias = 0.0f , float logit_softcap = 0.0f , ggml_prec prec = GGML_PREC_F32 , 7677ggml_type type_K = GGML_TYPE_F16 , ggml_type type_V = GGML_TYPE_F16 , std::array < int32_t, 4 > permute = { 0 , 1 , 2 , 3 }, 7678bool kv_view = true, bool v_is_view_of_k = false, int64_t n_kv_max = 0 ) 7679: hsk ( hsk ), hsv ( hsv ), nh ( nh ), nr23 ( nr23 ), kv ( kv ), nb ( nb ), mask ( mask ), sinks ( sinks ), max_bias ( max_bias ), logit_softcap ( logit_softcap ), prec ( prec ), 7680type_K ( type_K ), type_V ( type_V ), permute ( permute ), kv_view ( kv_view ), v_is_view_of_k ( v_is_view_of_k ), n_kv_max ( n_kv_max ) {} 7681 7682ggml_tensor * build_graph (ggml_context * ctx ) override { 7683const int64_t hsk_padded = GGML_PAD ( hsk , ggml_blck_size ( type_K )); 7684const int64_t hsv_padded = GGML_PAD ( hsv , ggml_blck_size ( type_V )); 7685 7686auto const & create_permuted = [ & ](ggml_type type , int64_t ne0 , int64_t ne1 , int64_t ne2 , int64_t ne3 , bool is_view ) -> ggml_tensor * { 7687int64_t ne [ 4 ] = { ne0 , ne1 , ne2 , ne3 }; 7688int64_t ne_perm [ 4 ]; 7689for (int i = 0 ; i < 4 ; ++ i ) { 7690ne_perm [ permute [ i ]] = ne [ i ]; 7691} 7692ggml_tensor * t ; 7693if ( is_view ) { 7694ggml_tensor * t0 = ggml_new_tensor_4d ( ctx , type , ne_perm [ 0 ], 2 * ne_perm [ 1 ], ne_perm [ 2 ], ne_perm [ 3 ]); 7695t = ggml_view_4d ( ctx , t0 , ne_perm [ 0 ], ne_perm [ 1 ], ne_perm [ 2 ], ne_perm [ 3 ], t0 -> nb [ 1 ], t0 -> nb [ 2 ], t0 -> nb [ 3 ], 0 ); 7696} else { 7697t = ggml_new_tensor_4d ( ctx , type , ne_perm [ 0 ], ne_perm [ 1 ], ne_perm [ 2 ], ne_perm [ 3 ]); 7698} 7699if ( permute != std::array < int32_t, 4 > { 0 , 1 , 2 , 3 }) { 7700t = ggml_permute ( ctx , t , permute [ 0 ], permute [ 1 ], permute [ 2 ], permute [ 3 ]); 7701} 7702return t ; 7703}; 7704 7705ggml_tensor * q = create_permuted ( GGML_TYPE_F32 , hsk_padded , nb , nh * nr23 [ 0 ], nr23 [ 1 ], false); 7706ggml_set_name ( q , "q" ); 7707 7708ggml_tensor * k = create_permuted ( type_K , hsk_padded , kv , nh , nr23 [ 1 ], kv_view ); // the K tensor is usually a view of the K cache 7709ggml_set_name ( k , "k" ); 7710 7711ggml_tensor * v = nullptr ; 7712if ( v_is_view_of_k ) { 7713// the V cache is a sub-view of the K cache. this is used by some MLA-based models 7714// for more info: 7715// - https://github.com/ggml-org/llama.cpp/pull/13435 7716// - https://github.com/ggml-org/llama.cpp/pull/18953#issuecomment-3774948392 7717// - https://github.com/ggml-org/llama.cpp/pull/18986 7718GGML_ASSERT ( type_K == type_V && hsv_padded <= hsk_padded ); 7719 7720v = ggml_view_4d ( ctx , k , hsv_padded , kv , nh , nr23 [ 1 ], k -> nb [ 1 ], k -> nb [ 2 ], k -> nb [ 3 ], 0 ); 7721} else { 7722v = create_permuted ( type_V , hsv_padded , kv , nh , nr23 [ 1 ], kv_view ); // the V tensor is usually a view of the V cache 7723} 7724ggml_set_name ( v , "v" ); 7725 7726ggml_tensor * m = nullptr ; 7727if ( mask ) { 7728m = ggml_new_tensor_4d ( ctx , GGML_TYPE_F16 , kv , nb , 1 , nr23 [ 1 ]); 7729ggml_set_name ( m , "m" ); 7730} 7731 7732ggml_tensor * s = nullptr ; 7733if ( sinks ) { 7734s = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , q -> ne [ 2 ]); 7735ggml_set_name ( s , "s" ); 7736} 7737 7738ggml_tensor * out = ggml_flash_attn_ext ( ctx , q , k , v , m , 1.0f / sqrtf ( hsk ), max_bias , logit_softcap ); 7739ggml_flash_attn_ext_add_sinks ( out , s ); 7740ggml_flash_attn_ext_set_n_kv_max ( out , n_kv_max ); 7741ggml_prec_set_acc ( out , prec ); 7742ggml_set_name ( out , "out" ); 7743 7744return out ; 7745} 7746 7747void initialize_tensors (ggml_context * ctx ) override { 7748for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7749if ( strcmp ( t -> name , "s" ) == 0 ) { 7750// make the sink values more noticeable in order to trigger a test failure when the implementation is wrong 7751init_tensor_uniform ( t , -10.0f , 10.0f ); 7752} else if ( strcmp ( t -> name , "m" ) == 0 ) { 7753if ( n_kv_max > 0 ) { 7754init_tensor_kq_mask_sparse ( t , n_kv_max ); 7755} else { 7756init_tensor_kq_mask ( t ); 7757} 7758} else { 7759init_tensor_uniform ( t ); 7760} 7761} 7762} 7763 7764bool grad_precise () override { 7765return true; 7766} 7767}; 7768 7769// GGML_OP_CROSS_ENTROPY_LOSS 7770struct test_cross_entropy_loss : public test_case { 7771const ggml_type type ; 7772const std::array < int64_t, 4 > ne ; 7773 7774std::string vars () override { 7775return VARS_TO_STR2 ( type , ne ); 7776} 7777 7778test_cross_entropy_loss (ggml_type type = GGML_TYPE_F32 , 7779std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7780: type ( type ), ne ( ne ) {} 7781 7782ggml_tensor * build_graph (ggml_context * ctx ) override { 7783ggml_tensor * logits = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7784ggml_set_param ( logits ); 7785ggml_set_name ( logits , "logits" ); 7786 7787ggml_tensor * labels = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7788// The labels are assumed to be constant -> no gradients. 7789ggml_set_name ( labels , "labels" ); 7790 7791// Ensure labels add up to 1: 7792labels = ggml_soft_max ( ctx , labels ); 7793ggml_set_name ( labels , "labels_normalized" ); 7794 7795ggml_tensor * out = ggml_cross_entropy_loss ( ctx , logits , labels ); 7796ggml_set_name ( out , "out" ); 7797 7798return out ; 7799} 7800 7801void initialize_tensors (ggml_context * ctx ) override { 7802// For larger abs. diffs between logits softmax is more linear, therefore more precise num. gradients. 7803for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7804init_tensor_uniform ( t , -100.0f , 100.0f ); 7805} 7806} 7807 7808float grad_eps () override { 7809return 1.0f ; 7810} 7811 7812bool grad_precise () override { 7813return true; 7814} 7815}; 7816 7817// GGML_OP_CROSS_ENTROPY_LOSS_BACK 7818struct test_cross_entropy_loss_back : public test_case { 7819const ggml_type type ; 7820const std::array < int64_t, 4 > ne ; 7821 7822std::string vars () override { 7823return VARS_TO_STR2 ( type , ne ); 7824} 7825 7826test_cross_entropy_loss_back (ggml_type type = GGML_TYPE_F32 , 7827std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7828: type ( type ), ne ( ne ) {} 7829 7830ggml_tensor * build_graph (ggml_context * ctx ) override { 7831ggml_tensor * grad = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , 1 ); 7832ggml_set_name ( grad , "grad" ); 7833 7834ggml_tensor * logits = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7835ggml_set_name ( logits , "logits" ); 7836 7837ggml_tensor * labels = ggml_new_tensor ( ctx , type , 4 , ne . data ()); 7838ggml_set_name ( labels , "labels" ); 7839 7840// Ensure labels add up to 1: 7841labels = ggml_soft_max ( ctx , labels ); 7842ggml_set_name ( labels , "labels_normalized" ); 7843 7844ggml_tensor * out = ggml_cross_entropy_loss_back ( ctx , grad , logits , labels ); 7845ggml_set_name ( out , "out" ); 7846 7847return out ; 7848} 7849}; 7850 7851// GGML_OP_OPT_STEP_ADAMW 7852struct test_opt_step_adamw : public test_case { 7853const ggml_type type ; 7854const std::array < int64_t, 4 > ne ; 7855 7856std::string vars () override { 7857return VARS_TO_STR2 ( type , ne ); 7858} 7859 7860test_opt_step_adamw (ggml_type type = GGML_TYPE_F32 , 7861std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7862: type ( type ), ne ( ne ) {} 7863 7864ggml_tensor * build_graph (ggml_context * ctx ) override { 7865ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7866ggml_set_param ( a ); // Despite tensor a having gradients the output tensor will not. 7867ggml_set_name ( a , "a" ); 7868 7869ggml_tensor * grad = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7870ggml_set_name ( grad , "grad" ); 7871 7872ggml_tensor * grad_m = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7873ggml_set_name ( grad_m , "grad_m" ); 7874 7875ggml_tensor * grad_v = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7876ggml_set_name ( grad_v , "grad_v" ); 7877 7878ggml_tensor * adamw_params = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , 7 ); 7879ggml_set_name ( adamw_params , "adamw_params" ); 7880 7881ggml_tensor * out = ggml_opt_step_adamw ( ctx , a , grad , grad_m , grad_v , adamw_params ); 7882ggml_set_name ( out , "out" ); 7883 7884return out ; 7885} 7886 7887void initialize_tensors (ggml_context * ctx ) override { 7888for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7889init_tensor_uniform ( t , 0.0f , 1.0f ); // grad_v and adamw_params need non-negative values. 7890} 7891} 7892 7893bool grad_precise () override { 7894return true; 7895} 7896}; 7897 7898// GGML_OP_OPT_STEP_SGD 7899struct test_opt_step_sgd : public test_case { 7900const ggml_type type ; 7901const std::array < int64_t, 4 > ne ; 7902 7903std::string vars () override { return VARS_TO_STR2 ( type , ne ); } 7904 7905test_opt_step_sgd (ggml_type type = GGML_TYPE_F32 , 7906std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7907: type ( type ), ne ( ne ) {} 7908 7909ggml_tensor * build_graph (ggml_context * ctx ) override { 7910ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7911ggml_set_param ( a ); // Despite tensor a having gradients the output tensor will not. 7912ggml_set_name ( a , "a" ); 7913 7914ggml_tensor * grad = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7915ggml_set_name ( grad , "grad" ); 7916 7917ggml_tensor * sgd_params = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , 2 ); 7918ggml_set_name ( sgd_params , "sgd_params" ); 7919 7920ggml_tensor * out = ggml_opt_step_sgd ( ctx , a , grad , sgd_params ); 7921 7922ggml_set_name ( out , "out" ); 7923 7924return out ; 7925} 7926 7927void initialize_tensors (ggml_context * ctx ) override { 7928for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7929init_tensor_uniform ( t , 0.0f , 1.0f ); // sgd_params need non-negative values. 7930} 7931} 7932 7933bool grad_precise () override { 7934return true; 7935} 7936}; 7937 7938// GGML_OP_CUMSUM 7939struct test_cumsum : public test_case { 7940const ggml_type type ; 7941const std::array < int64_t, 4 > ne ; 7942 7943std::string vars () override { return VARS_TO_STR2 ( type , ne ); } 7944 7945test_cumsum (ggml_type type = GGML_TYPE_F32 , 7946std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7947: type ( type ), ne ( ne ) {} 7948 7949ggml_tensor * build_graph (ggml_context * ctx ) override { 7950ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7951ggml_set_param ( a ); 7952ggml_set_name ( a , "a" ); 7953 7954ggml_tensor * out = ggml_cumsum ( ctx , a ); 7955 7956ggml_set_name ( out , "out" ); 7957 7958return out ; 7959} 7960 7961void initialize_tensors (ggml_context * ctx ) override { 7962for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7963init_tensor_uniform ( t , -1.0f , 1.0f ); 7964} 7965} 7966}; 7967 7968// GGML_OP_XIELU 7969struct test_xielu : public test_case { 7970const ggml_type type ; 7971const std::array < int64_t, 4 > ne ; 7972 7973std::string vars () override { return VARS_TO_STR2 ( type , ne ); } 7974 7975test_xielu (ggml_type type = GGML_TYPE_F32 , 7976std::array < int64_t, 4 > ne = { 10 , 5 , 4 , 3 }) 7977: type ( type ), ne ( ne ) {} 7978 7979ggml_tensor * build_graph (ggml_context * ctx ) override { 7980ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 7981ggml_set_param ( a ); 7982ggml_set_name ( a , "a" ); 7983 7984float alpha_n = 4.0f ; 7985float alpha_p = 20.0f ; 7986float beta = 0.5f ; 7987float eps = 0.0000001f ; 7988 7989ggml_tensor * out = ggml_xielu ( ctx , a , alpha_n , alpha_p , beta , eps ); 7990 7991ggml_set_name ( out , "out" ); 7992 7993return out ; 7994} 7995 7996void initialize_tensors (ggml_context * ctx ) override { 7997for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 7998init_tensor_uniform ( t , -1.0f , 1.0f ); 7999} 8000} 8001}; 8002 8003// GGML_OP_TRI 8004struct test_tri : public test_case { 8005const ggml_type type ; 8006const std::array < int64_t, 4 > ne ; 8007const ggml_tri_type tri_type ; 8008 8009std::string vars () override { return VARS_TO_STR3 ( type , ne , tri_type ); } 8010 8011test_tri (ggml_tri_type tri_type , ggml_type type = GGML_TYPE_F32 , 8012std::array < int64_t, 4 > ne = { 10 , 10 , 4 , 3 }) 8013: type ( type ), ne ( ne ), tri_type ( tri_type ) { 8014GGML_ASSERT ( ne [ 0 ] == ne [ 1 ]); 8015} 8016 8017ggml_tensor * build_graph (ggml_context * ctx ) override { 8018ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 8019ggml_set_param ( a ); 8020ggml_set_name ( a , "a" ); 8021 8022ggml_tensor * out = ggml_tri ( ctx , a , tri_type ); 8023 8024ggml_set_name ( out , "out" ); 8025 8026return out ; 8027} 8028 8029void initialize_tensors (ggml_context * ctx ) override { 8030for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 8031init_tensor_uniform ( t , -1.0f , 1.0f ); 8032} 8033} 8034}; 8035 8036// GGML_OP_FILL 8037struct test_fill : public test_case { 8038const ggml_type type ; 8039const std::array < int64_t, 4 > ne ; 8040float c ; 8041 8042std::string vars () override { return VARS_TO_STR3 ( type , ne , c ); } 8043 8044test_fill (float c , ggml_type type = GGML_TYPE_F32 , 8045std::array < int64_t, 4 > ne = { 10 , 10 , 4 , 3 }) 8046: type ( type ), ne ( ne ), c ( c ) {} 8047 8048ggml_tensor * build_graph (ggml_context * ctx ) override { 8049ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 8050ggml_set_param ( a ); 8051ggml_set_name ( a , "a" ); 8052 8053ggml_tensor * out = ggml_fill ( ctx , a , c ); 8054 8055ggml_set_name ( out , "out" ); 8056 8057return out ; 8058} 8059}; 8060 8061// GGML_OP_SOLVE_TRI 8062struct test_solve_tri : public test_case { 8063const ggml_type type ; 8064const std::array < int64_t, 4 > ne_lhs ; 8065const std::array < int64_t, 4 > ne_rhs ; 8066 8067std::string vars () override { return VARS_TO_STR3 ( type , ne_lhs , ne_rhs ); } 8068 8069uint64_t op_flops (ggml_tensor * t ) override { 8070GGML_UNUSED ( t ); 8071int64_t n = ne_lhs [ 0 ]; 8072int64_t k = ne_rhs [ 0 ]; 8073int64_t batch = ne_lhs [ 2 ] * ne_lhs [ 3 ]; 8074// n * (n + 1) / 2 non-zero elements of lhs, 2 flops each, for each col of rhs 8075return n * ( n + 1 ) * k * batch ; 8076} 8077 8078test_solve_tri (ggml_type type = GGML_TYPE_F32 , 8079std::array < int64_t, 4 > ne_lhs = { 10 , 10 , 4 , 3 }, 8080std::array < int64_t, 4 > ne_rhs = { 3 , 10 , 4 , 3 } 8081) 8082: type ( type ), ne_lhs ( ne_lhs ), ne_rhs ( ne_rhs ) {} 8083 8084ggml_tensor * build_graph (ggml_context * ctx ) override { 8085ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne_lhs [ 0 ], ne_lhs [ 1 ], ne_lhs [ 2 ], ne_lhs [ 3 ]); 8086ggml_set_param ( a ); 8087ggml_set_name ( a , "a" ); 8088 8089ggml_tensor * b = ggml_new_tensor_4d ( ctx , type , ne_rhs [ 0 ], ne_rhs [ 1 ], ne_rhs [ 2 ], ne_rhs [ 3 ]); 8090ggml_set_param ( b ); 8091ggml_set_name ( b , "b" ); 8092 8093ggml_tensor * out = ggml_solve_tri ( ctx , a , b , true, true, false); 8094ggml_set_name ( out , "out" ); 8095 8096return out ; 8097} 8098 8099void initialize_tensors (ggml_context * ctx ) override { 8100for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 8101if ( strcmp ( t -> name , "a" ) == 0 ) { 8102// note: avoid zeros in the diagonal 8103init_tensor_tril ( t , 0.1 , 1.0f ); 8104} else { 8105init_tensor_uniform ( t , -1.0f , 1.0f ); 8106} 8107} 8108} 8109}; 8110 8111// GGML_OP_DIAG 8112struct test_diag : public test_case { 8113const ggml_type type ; 8114const std::array < int64_t, 4 > ne ; 8115 8116std::string vars () override { return VARS_TO_STR2 ( type , ne ); } 8117 8118test_diag (ggml_type type = GGML_TYPE_F32 , 8119std::array < int64_t, 4 > ne = { 10 , 1 , 4 , 3 }) 8120: type ( type ), ne ( ne ) {} 8121 8122ggml_tensor * build_graph (ggml_context * ctx ) override { 8123GGML_ASSERT ( ne [ 1 ] == 1 ); 8124ggml_tensor * a = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 8125ggml_set_param ( a ); 8126ggml_set_name ( a , "a" ); 8127 8128ggml_tensor * out = ggml_diag ( ctx , a ); 8129ggml_set_name ( out , "out" ); 8130 8131return out ; 8132} 8133}; 8134 8135// GGML_OP_LIGHTNING_INDEXER 8136struct test_lightning_indexer : public test_case { 8137const int64_t hsk ; // indexer K head size 8138const int64_t nh ; // num indexer heads 8139const int64_t kv ; // kv size 8140const int64_t nb ; // batch size 8141const int64_t ns ; // num streams 8142const int64_t nm ; // ne[3] of mask 8143 8144const ggml_type type_K ; 8145 8146std::string vars () override { 8147return VARS_TO_STR7 ( hsk , nh , kv , nb , ns , nm , type_K ); 8148} 8149 8150double max_nmse_err () override { 8151return 1e-6 ; 8152} 8153 8154uint64_t op_flops (ggml_tensor * t ) override { 8155GGML_UNUSED ( t ); 8156return (( 2 * hsk + 2 ) * nh + 1 ) * kv * nb * ns ; 8157} 8158 8159test_lightning_indexer (int64_t hsk = 128 , int64_t nh = 64 , int64_t kv = 256 , int64_t nb = 128 , int64_t ns = 1 , int64_t nm = 1 , ggml_type type_K = GGML_TYPE_F16 ) 8160: hsk ( hsk ), nh ( nh ), kv ( kv ), nb ( nb ), ns ( ns ), nm ( nm ), type_K ( type_K ) {} 8161 8162ggml_tensor * build_graph (ggml_context * ctx ) override { 8163ggml_tensor * q = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , hsk , nh , nb , ns ); 8164ggml_set_param ( q ); 8165ggml_set_name ( q , "q" ); 8166 8167ggml_tensor * k = ggml_new_tensor_4d ( ctx , type_K , hsk , 1 , kv , ns ); 8168ggml_set_param ( k ); 8169ggml_set_name ( k , "k" ); 8170 8171ggml_tensor * w = ggml_new_tensor_4d ( ctx , GGML_TYPE_F32 , nh , nb , 1 , ns ); 8172ggml_set_param ( w ); 8173ggml_set_name ( w , "w" ); 8174 8175ggml_tensor * m = ggml_new_tensor_4d ( ctx , GGML_TYPE_F16 , kv , nb , 1 , nm ); 8176ggml_set_param ( m ); 8177ggml_set_name ( m , "m" ); 8178 8179ggml_tensor * out = ggml_lightning_indexer ( ctx , q , k , w , m ); 8180ggml_set_name ( out , "out" ); 8181 8182return out ; 8183} 8184 8185void initialize_tensors (ggml_context * ctx ) override { 8186for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 8187if ( strcmp ( t -> name , "m" ) == 0 ) { 8188init_tensor_kq_mask ( t ); 8189} else { 8190init_tensor_uniform ( t ); 8191} 8192} 8193} 8194}; 8195 8196// Deserializable generic test case 8197struct input_tensor { 8198ggml_type type ; 8199std::array < int64_t, 4 > ne ; 8200std::array < size_t, 4 > nb ; // strides (0 = use default contiguous strides) 8201}; 8202 8203static bool is_non_contiguous ( const input_tensor & src ) { 8204if ( src . nb [ 0 ] == 0 ) { 8205return false; 8206} 8207const size_t default_nb0 = ggml_type_size ( src . type ); 8208const size_t default_nb1 = default_nb0 * ( src . ne [ 0 ] / ggml_blck_size ( src . type )); 8209const size_t default_nb2 = default_nb1 * src . ne [ 1 ]; 8210const size_t default_nb3 = default_nb2 * src . ne [ 2 ]; 8211return src . nb [ 0 ] != default_nb0 || 8212src . nb [ 1 ] != default_nb1 || 8213src . nb [ 2 ] != default_nb2 || 8214src . nb [ 3 ] != default_nb3 ; 8215} 8216 8217static std::string var_to_str ( const std::vector < input_tensor >& sources ) { 8218std::ostringstream oss ; 8219bool first = true; 8220for ( const auto & src : sources ) { 8221if (! first ) oss << "," ; 8222oss << ggml_type_name ( src . type ) << "[" << src . ne [ 0 ] << "," << src . ne [ 1 ] << "," << src . ne [ 2 ] << "," << src . ne [ 3 ] << "]" ; 8223if ( is_non_contiguous ( src )) { 8224oss << "nb[" << src . nb [ 0 ] << "," << src . nb [ 1 ] << "," << src . nb [ 2 ] << "," << src . nb [ 3 ] << "]" ; 8225} 8226first = false; 8227} 8228return oss . str (); 8229} 8230 8231static std::string var_to_str ( const std::array < int32_t, GGML_MAX_OP_PARAMS / sizeof (int32_t) >& params ) { 8232std::ostringstream oss ; 8233oss << "[" ; 8234bool first = true; 8235for (size_t i = 0 ; i < params . size (); ++ i ) { 8236if ( params [ i ] != 0 ) { 8237if (! first ) oss << "," ; 8238oss << i << ":" << params [ i ]; 8239first = false; 8240} 8241} 8242oss << "]" ; 8243return oss . str (); 8244} 8245 8246 8247struct test_generic_op : public test_case { 8248const ggml_op op ; 8249const ggml_type type ; 8250const std::array < int64_t, 4 > ne ; 8251const std::array < int32_t, GGML_MAX_OP_PARAMS / sizeof (int32_t) > op_params ; 8252 8253const std::vector < input_tensor > sources ; 8254const std::string name ; 8255 8256std::string vars () override { 8257if ( name . empty ()) { 8258return VARS_TO_STR4 ( type , ne , op_params , sources ); 8259} 8260 8261return VARS_TO_STR5 ( name , type , ne , op_params , sources ); 8262} 8263 8264test_generic_op (ggml_op op , ggml_type type , std::array < int64_t, 4 > ne , 8265std::array < int32_t, GGML_MAX_OP_PARAMS / sizeof (int32_t) > op_params , 8266std::vector < input_tensor > sources , std::string name = "" ) 8267: op ( op ), type ( type ), ne ( ne ), op_params ( op_params ), sources ( sources ), name (std:: move ( name )) {} 8268 8269ggml_tensor * build_graph (ggml_context * ctx ) override { 8270const size_t source_count = std:: min ( sources . size (), (size_t) GGML_MAX_SRC ); 8271 8272std::array < ggml_tensor * , GGML_MAX_SRC > source_tensors ; 8273for (size_t i = 0 ; i < source_count ; ++ i ) { 8274const input_tensor & src = sources [ i ]; 8275 8276if ( is_non_contiguous ( src )) { 8277size_t total_size ; 8278const size_t blck_size = ggml_blck_size ( src . type ); 8279if ( blck_size == 1 ) { 8280total_size = ggml_type_size ( src . type ); 8281for (int d = 0 ; d < 4 ; d ++ ) { 8282total_size += ( src . ne [ d ] - 1 ) * src . nb [ d ]; 8283} 8284} else { 8285total_size = src . ne [ 0 ] * src . nb [ 0 ] / blck_size ; 8286for (int d = 1 ; d < 4 ; d ++ ) { 8287total_size += ( src . ne [ d ] - 1 ) * src . nb [ d ]; 8288} 8289} 8290 8291// Convert bytes to elements, padded to block size for quantized types 8292const size_t type_size = ggml_type_size ( src . type ); 8293size_t backing_elements = ( total_size * blck_size + type_size - 1 ) / type_size ; 8294backing_elements = (( backing_elements + blck_size - 1 ) / blck_size ) * blck_size ; 8295ggml_tensor * backing = ggml_new_tensor_1d ( ctx , src . type , backing_elements ); 8296source_tensors [ i ] = ggml_view_4d ( ctx , backing , 8297src . ne [ 0 ], src . ne [ 1 ], src . ne [ 2 ], src . ne [ 3 ], 8298src . nb [ 1 ], src . nb [ 2 ], src . nb [ 3 ], 0 ); 8299// nb[0] does not get set by view_4d, so set it manually 8300source_tensors [ i ] -> nb [ 0 ] = src . nb [ 0 ]; 8301} else { 8302source_tensors [ i ] = ggml_new_tensor_4d ( ctx , src . type , src . ne [ 0 ], src . ne [ 1 ], src . ne [ 2 ], src . ne [ 3 ]); 8303} 8304} 8305 8306// Ops with an inplace flag create a view of src[0] as their output. 8307bool inplace = false; 8308if ( op == GGML_OP_SET || op == GGML_OP_ACC ) { 8309inplace = op_params [ 4 ] != 0 ; 8310} else if ( op == GGML_OP_ADD_REL_POS ) { 8311inplace = op_params [ 0 ] != 0 ; 8312} 8313 8314ggml_tensor * out ; 8315if ( inplace && source_count > 0 ) { 8316out = ggml_view_tensor ( ctx , source_tensors [ 0 ]); 8317} else { 8318out = ggml_new_tensor_4d ( ctx , type , ne [ 0 ], ne [ 1 ], ne [ 2 ], ne [ 3 ]); 8319} 8320out -> op = op ; 8321for (size_t i = 0 ; i < source_count ; ++ i ) { 8322out -> src [ i ] = source_tensors [ i ]; 8323} 8324 8325memcpy ( out -> op_params , op_params . data (), GGML_MAX_OP_PARAMS ); 8326ggml_set_name ( out , "out" ); 8327 8328return out ; 8329} 8330 8331double max_nmse_err () override { 8332switch ( op ) { 8333case GGML_OP_MUL_MAT : 8334case GGML_OP_MUL_MAT_ID : 8335case GGML_OP_OUT_PROD : 8336case GGML_OP_CONV_TRANSPOSE_2D : 8337case GGML_OP_IM2COL : 8338case GGML_OP_CONV_2D : 8339case GGML_OP_CONV_3D : 8340case GGML_OP_SET_ROWS : 8341case GGML_OP_CPY : 8342return 5e-4 ; 8343case GGML_OP_SOFT_MAX : 8344return 1e-6 ; 8345case GGML_OP_RWKV_WKV7 : 8346return 5e-3 ; 8347case GGML_OP_FLASH_ATTN_EXT : 8348{ 8349// Scale error with kv length to account for accumulating floating point error 8350const int64_t kv = sources [ 1 ]. ne [ 1 ]; 8351return 5e-4 * std:: max ( 1.0 , kv / 20000.0 ); 8352} 8353default : 8354return 1e-7 ; 8355} 8356} 8357 8358void initialize_tensors (ggml_context * ctx ) override { 8359ggml_tensor * out = ggml_get_tensor ( ctx , "out" ); 8360 8361std::random_device rd ; 8362std::default_random_engine rng ( rd ()); 8363 8364for (size_t i = 0 ; i < sources . size () && i < GGML_MAX_SRC ; i ++ ) { 8365ggml_tensor * t = out -> src [ i ]; 8366if (! t ) { 8367break ; 8368} 8369 8370// FLASH_ATTN_EXT: src[3] is the KQ mask 8371if ( op == GGML_OP_FLASH_ATTN_EXT && i == 3 ) { 8372init_tensor_kq_mask ( t ); 8373continue ; 8374} 8375 8376if ( t -> type == GGML_TYPE_I32 || t -> type == GGML_TYPE_I64 ) { 8377if ( op == GGML_OP_GET_ROWS || op == GGML_OP_GET_ROWS_BACK ) { 8378const int64_t num_rows = sources [ 0 ]. ne [ 1 ]; 8379const int64_t nels = ggml_nelements ( t ); 8380std::vector < int32_t > data (nels); 8381std::uniform_int_distribution < int32_t > dist ( 0 , num_rows - 1 ); 8382for (int64_t i = 0 ; i < nels ; i ++ ) { 8383data [ i ] = dist ( rng ); 8384} 8385ggml_backend_tensor_set ( t , data . data (), 0 , nels * sizeof (int32_t)); 8386} else if ( op == GGML_OP_SET_ROWS ) { 8387init_set_rows_row_ids ( t , ne [ 1 ]); 8388} else if ( op == GGML_OP_ROPE ) { 8389const int mode = op_params [ 2 ]; 8390const int64_t nels = ( mode & GGML_ROPE_TYPE_MROPE ) ? ne [ 2 ] * 4 : ne [ 2 ]; 8391std::vector < int32_t > data (nels); 8392std::uniform_int_distribution < int32_t > dist ( 0 , ne [ 2 ] - 1 ); 8393for (int64_t i = 0 ; i < nels ; i ++ ) { 8394data [ i ] = dist ( rng ); 8395} 8396ggml_backend_tensor_set ( t , data . data (), 0 , nels * sizeof (int32_t)); 8397} else if ( op == GGML_OP_MUL_MAT_ID || op == GGML_OP_ADD_ID ) { 8398const int64_t n_expert = ( op == GGML_OP_MUL_MAT_ID ) ? sources [ 0 ]. ne [ 2 ] : sources [ 1 ]. ne [ 1 ]; 8399for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 8400std::vector < int32_t > data ( t -> ne [ 0 ]); 8401for (int32_t i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 8402data [ i ] = i % n_expert ; 8403} 8404std:: shuffle ( data . begin (), data . end (), rng ); 8405ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 8406} 8407} else if ( op == GGML_OP_SSM_SCAN ) { 8408for (int64_t r = 0 ; r < ggml_nrows ( t ); r ++ ) { 8409std::vector < int32_t > data ( t -> ne [ 0 ]); 8410for (int32_t i = 0 ; i < t -> ne [ 0 ]; i ++ ) { 8411data [ i ] = i ; 8412} 8413std:: shuffle ( data . begin (), data . end (), rng ); 8414ggml_backend_tensor_set ( t , data . data (), r * t -> nb [ 1 ], t -> ne [ 0 ] * sizeof (int32_t)); 8415} 8416} else { 8417init_tensor_uniform ( t ); 8418} 8419} else { 8420init_tensor_uniform ( t ); 8421} 8422} 8423} 8424}; 8425 8426 8427enum llm_norm_type { 8428LLM_NORM , 8429LLM_NORM_RMS , 8430}; 8431 8432struct llama_hparams { 8433uint32_t n_vocab ; 8434uint32_t n_embd ; 8435uint32_t n_head ; 8436uint32_t n_head_kv ; 8437static constexpr uint32_t n_layer = 1 ; 8438uint32_t n_rot ; 8439uint32_t n_embd_head ; // dimension of values (d_v) 8440uint32_t n_ff ; 8441 8442float f_norm_eps ; 8443float f_norm_rms_eps ; 8444 8445// cparams 8446static constexpr uint32_t n_ctx = 512 ; // user-specified context size 8447static constexpr uint32_t n_ctx_orig = n_ctx ; 8448 8449// batch 8450int32_t n_tokens ; 8451 8452// llm_build_context 8453static constexpr int32_t n_kv = 32 ; // size of KV cache to consider (n_kv <= n_ctx 8454static constexpr int32_t kv_head = 1 ; // index of where we store new KV data in the cache 8455 8456uint32_t n_embd_gqa () const { // dimension of key embeddings across all k-v heads 8457return n_embd_head * n_head_kv ; 8458} 8459}; 8460 8461// LLM base class 8462struct test_llm : public test_case { 8463llama_hparams hp ; 8464 8465protected : 8466test_llm (llama_hparams hp ) 8467: hp (std:: move ( hp )) { 8468} 8469 8470public : 8471struct ggml_tensor * llm_build_norm ( 8472struct ggml_context * ctx , 8473struct ggml_tensor * cur , 8474struct ggml_tensor * mw , 8475struct ggml_tensor * mb , 8476llm_norm_type type ) { 8477switch ( type ) { 8478case LLM_NORM : cur = ggml_norm ( ctx , cur , hp . f_norm_eps ); break ; 8479case LLM_NORM_RMS : cur = ggml_rms_norm ( ctx , cur , hp . f_norm_rms_eps ); break ; 8480} 8481cur = ggml_mul ( ctx , cur , mw ); 8482if ( mb ) { 8483cur = ggml_add ( ctx , cur , mb ); 8484} 8485return cur ; 8486} 8487 8488void llm_build_kv_store ( 8489struct ggml_context * ctx , 8490struct ggml_tensor * k_l , 8491struct ggml_tensor * v_l , 8492struct ggml_tensor * k_cur , 8493struct ggml_tensor * v_cur ) { 8494// compute the transposed [n_tokens, n_embd] V matrix 8495struct ggml_tensor * v_cur_t = ggml_transpose ( ctx , ggml_reshape_2d ( ctx , v_cur , hp . n_embd_gqa (), hp . n_tokens )); 8496 8497struct ggml_tensor * k_cache_view = ggml_view_1d ( ctx , k_l , hp . n_tokens * hp . n_embd_gqa (), 8498( ggml_row_size ( k_l -> type , hp . n_embd_gqa ())) * hp . kv_head ); 8499 8500struct ggml_tensor * v_cache_view = ggml_view_2d ( ctx , v_l , hp . n_tokens , hp . n_embd_gqa (), 8501( hp . n_ctx ) * ggml_element_size ( v_l ), 8502( hp . kv_head ) * ggml_element_size ( v_l )); 8503 8504// important: storing RoPE-ed version of K in the KV cache! 8505ggml_cpy ( ctx , k_cur , k_cache_view ); 8506ggml_cpy ( ctx , v_cur_t , v_cache_view ); 8507} 8508 8509struct ggml_tensor * llm_build_kqv ( 8510struct ggml_context * ctx , 8511struct ggml_tensor * k_l , 8512struct ggml_tensor * v_l , 8513struct ggml_tensor * q_cur , 8514struct ggml_tensor * kq_mask , 8515float kq_scale ) { 8516struct ggml_tensor * q = ggml_permute ( ctx , q_cur , 0 , 2 , 1 , 3 ); 8517 8518struct ggml_tensor * k = 8519ggml_view_3d ( ctx , k_l , 8520hp . n_embd_head , hp . n_kv , hp . n_head_kv , 8521ggml_row_size ( k_l -> type , hp . n_embd_gqa ()), 8522ggml_row_size ( k_l -> type , hp . n_embd_head ), 85230 ); 8524 8525struct ggml_tensor * kq = ggml_mul_mat ( ctx , k , q ); 8526 8527kq = ggml_soft_max_ext ( ctx , kq , kq_mask , kq_scale , 0.0f ); 8528 8529// split cached v into n_head heads 8530struct ggml_tensor * v = 8531ggml_view_3d ( ctx , v_l , 8532hp . n_kv , hp . n_embd_head , hp . n_head_kv , 8533ggml_element_size ( v_l ) * hp . n_ctx , 8534ggml_element_size ( v_l ) * hp . n_ctx * hp . n_embd_head , 85350 ); 8536 8537struct ggml_tensor * kqv = ggml_mul_mat ( ctx , v , kq ); 8538 8539struct ggml_tensor * kqv_merged = ggml_permute ( ctx , kqv , 0 , 2 , 1 , 3 ); 8540 8541struct ggml_tensor * cur = ggml_cont_2d ( ctx , kqv_merged , hp . n_embd_head * hp . n_head , hp . n_tokens ); 8542 8543struct ggml_tensor * wo = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_embd ); 8544cur = ggml_mul_mat ( ctx , wo , cur ); 8545 8546return cur ; 8547} 8548 8549void initialize_tensors (ggml_context * ctx ) override { 8550for (ggml_tensor * t = ggml_get_first_tensor ( ctx ); t != NULL ; t = ggml_get_next_tensor ( ctx , t )) { 8551if ( t -> type == GGML_TYPE_I32 ) { 8552// pos 8553std::vector < int > data ( hp . n_tokens ); 8554for (int i = 0 ; i < hp . n_tokens ; i ++ ) { 8555data [ i ] = rand () % hp . n_ctx ; 8556} 8557ggml_backend_tensor_set ( t , data . data (), 0 , hp . n_tokens * sizeof (int)); 8558} else { 8559init_tensor_uniform ( t ); 8560} 8561} 8562} 8563}; 8564 8565// Llama 8566struct test_llama : public test_llm { 8567static constexpr float freq_base = 10000.0f ; 8568static constexpr float freq_scale = 1.0f ; 8569static constexpr float ext_factor = 0.0f ; 8570static constexpr float attn_factor = 1.0f ; 8571static constexpr float beta_fast = 32.0f ; 8572static constexpr float beta_slow = 1.0f ; 8573bool fused ; 8574 8575std::string op_desc (ggml_tensor * t ) override { 8576GGML_UNUSED ( t ); 8577return "LLAMA" ; 8578} 8579 8580std::string vars () override { 8581auto n_tokens = hp . n_tokens ; 8582return VARS_TO_STR1 ( n_tokens ); 8583} 8584 8585double max_nmse_err () override { 8586return 2e-3 ; 8587} 8588 8589bool run_whole_graph () override { return fused ; } 8590 8591test_llama (int n_tokens = 1 , bool fused = false) 8592: test_llm ({ 8593/*n_vocab =*/ 32000 , 8594/*n_embd =*/ 3200 , 8595/*n_head =*/ 32 , 8596/*n_head_kv =*/ 32 , 8597/*n_rot =*/ 100 , 8598/*n_embd_head =*/ 100 , 8599/*n_ff =*/ 8640 , 8600/*f_norm_eps =*/ 0.f , 8601/*f_norm_rms_eps =*/ 1e-5f , 8602/*n_tokens =*/ n_tokens , 8603}) 8604, fused ( fused ) 8605{ 8606} 8607 8608ggml_tensor * build_graph (ggml_context * ctx ) override { 8609struct ggml_tensor * cur ; 8610struct ggml_tensor * inpL ; 8611 8612inpL = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , hp . n_embd , hp . n_tokens ); 8613 8614// inp_pos - contains the positions 8615struct ggml_tensor * inp_pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , hp . n_tokens ); 8616 8617// KQ_mask (mask for 1 head, it will be broadcasted to all heads) 8618struct ggml_tensor * KQ_mask = ggml_new_tensor_3d ( ctx , GGML_TYPE_F16 , hp . n_kv , hp . n_tokens , 1 ); 8619 8620ggml_tensor * k_l = ggml_new_tensor_1d ( ctx , GGML_TYPE_F16 , 1638400 ); 8621ggml_tensor * v_l = ggml_new_tensor_1d ( ctx , GGML_TYPE_F16 , 1638400 ); 8622 8623for (uint32_t il = 0 ; il < hp . n_layer ; ++ il ) { 8624struct ggml_tensor * inpSA = inpL ; 8625 8626// norm 8627ggml_tensor * attn_norm = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8628cur = llm_build_norm ( ctx , inpL , attn_norm , nullptr , LLM_NORM_RMS ); 8629 8630// self-attention 8631{ 8632ggml_tensor * wq = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_embd ); 8633ggml_tensor * wk = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_embd_gqa ()); 8634ggml_tensor * wv = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_embd_gqa ()); 8635 8636// compute Q and K and RoPE them 8637struct ggml_tensor * Qcur = ggml_mul_mat ( ctx , wq , cur ); 8638struct ggml_tensor * Kcur = ggml_mul_mat ( ctx , wk , cur ); 8639struct ggml_tensor * Vcur = ggml_mul_mat ( ctx , wv , cur ); 8640 8641Qcur = ggml_rope_ext ( 8642ctx , ggml_reshape_3d ( ctx , Qcur , hp . n_embd_head , hp . n_head , hp . n_tokens ), inp_pos , nullptr , 8643hp . n_rot , 0 , hp . n_ctx_orig , freq_base , freq_scale , 8644ext_factor , attn_factor , beta_fast , beta_slow 8645); 8646 8647Kcur = ggml_rope_ext ( 8648ctx , ggml_reshape_3d ( ctx , Kcur , hp . n_embd_head , hp . n_head_kv , hp . n_tokens ), inp_pos , nullptr , 8649hp . n_rot , 0 , hp . n_ctx_orig , freq_base , freq_scale , 8650ext_factor , attn_factor , beta_fast , beta_slow 8651); 8652 8653llm_build_kv_store ( ctx , k_l , v_l , Kcur , Vcur ); 8654 8655cur = llm_build_kqv ( ctx , k_l , v_l , Qcur , KQ_mask , 1.0f / sqrtf (float( hp . n_embd_head ))); 8656} 8657 8658struct ggml_tensor * ffn_inp = ggml_add ( ctx , cur , inpSA ); 8659 8660// feed-forward network 8661ggml_tensor * ffn_norm = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8662cur = llm_build_norm ( ctx , ffn_inp , ffn_norm , nullptr , LLM_NORM_RMS ); 8663 8664ggml_tensor * ffn_gate = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_ff ); 8665ggml_tensor * ffn_down = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_ff , hp . n_embd ); 8666ggml_tensor * ffn_up = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_ff ); 8667struct ggml_tensor * tmp = ggml_mul_mat ( ctx , ffn_up , cur ); 8668cur = ggml_mul_mat ( ctx , ffn_gate , cur ); 8669cur = ggml_silu ( ctx , cur ); 8670cur = ggml_mul ( ctx , cur , tmp ); 8671cur = ggml_mul_mat ( ctx , ffn_down , cur ); 8672 8673cur = ggml_add ( ctx , cur , ffn_inp ); 8674 8675// input for next layer 8676inpL = cur ; 8677} 8678 8679cur = inpL ; 8680 8681ggml_tensor * output_norm = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8682cur = llm_build_norm ( ctx , cur , output_norm , nullptr , LLM_NORM_RMS ); 8683 8684// lm_head 8685ggml_tensor * output = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_vocab ); 8686cur = ggml_mul_mat ( ctx , output , cur ); 8687 8688return cur ; 8689} 8690}; 8691 8692// Falcon 8693struct test_falcon : public test_llm { 8694static constexpr float freq_base = 10000.0f ; 8695static constexpr float freq_scale = 1.0f ; 8696static constexpr float ext_factor = 0.0f ; 8697static constexpr float attn_factor = 1.0f ; 8698static constexpr float beta_fast = 32.0f ; 8699static constexpr float beta_slow = 1.0f ; 8700 8701std::string op_desc (ggml_tensor * t ) override { 8702GGML_UNUSED ( t ); 8703return "FALCON" ; 8704} 8705 8706std::string vars () override { 8707auto n_tokens = hp . n_tokens ; 8708return VARS_TO_STR1 ( n_tokens ); 8709} 8710 8711double max_nmse_err () override { 8712return 2e-3 ; 8713} 8714 8715test_falcon (int n_tokens = 1 ) 8716: test_llm ({ 8717/*n_vocab =*/ 32000 , 8718/*n_embd =*/ 3200 , 8719/*n_head =*/ 50 , 8720/*n_head_kv =*/ 1 , 8721/*n_rot =*/ 64 , 8722/*n_embd_head =*/ 64 , 8723/*n_ff =*/ 8640 , 8724/*f_norm_eps =*/ 1e-5f , 8725/*f_norm_rms_eps =*/ 0.f , 8726/*n_tokens =*/ n_tokens , 8727}) { 8728} 8729 8730ggml_tensor * build_graph (ggml_context * ctx ) override { 8731struct ggml_tensor * cur ; 8732struct ggml_tensor * inpL ; 8733 8734inpL = ggml_new_tensor_2d ( ctx , GGML_TYPE_F32 , hp . n_embd , hp . n_tokens ); 8735 8736// inp_pos - contains the positions 8737struct ggml_tensor * inp_pos = ggml_new_tensor_1d ( ctx , GGML_TYPE_I32 , hp . n_tokens ); 8738 8739// KQ_mask (mask for 1 head, it will be broadcasted to all heads) 8740struct ggml_tensor * KQ_mask = ggml_new_tensor_3d ( ctx , GGML_TYPE_F16 , hp . n_kv , hp . n_tokens , 1 ); 8741 8742ggml_tensor * k_l = ggml_new_tensor_1d ( ctx , GGML_TYPE_F16 , 1638400 ); 8743ggml_tensor * v_l = ggml_new_tensor_1d ( ctx , GGML_TYPE_F16 , 1638400 ); 8744 8745for (uint32_t il = 0 ; il < hp . n_layer ; ++ il ) { 8746// norm 8747ggml_tensor * attn_norm_w = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8748ggml_tensor * attn_norm_b = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8749ggml_tensor * attn_norm = llm_build_norm ( ctx , inpL , attn_norm_w , attn_norm_b , LLM_NORM ); 8750 8751// self-attention 8752{ 8753cur = attn_norm ; 8754 8755ggml_tensor * wqkv = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_embd + 2 * hp . n_embd_gqa ()); 8756 8757cur = ggml_mul_mat ( ctx , wqkv , cur ); 8758 8759struct ggml_tensor * Qcur = ggml_cont ( ctx , ggml_view_2d ( ctx , cur , hp . n_embd , hp . n_tokens , cur -> nb [ 1 ], 0 * sizeof (float) * ( hp . n_embd ))); 8760struct ggml_tensor * Kcur = ggml_cont ( ctx , ggml_view_2d ( ctx , cur , hp . n_embd_gqa (), hp . n_tokens , cur -> nb [ 1 ], 1 * sizeof (float) * ( hp . n_embd ))); 8761struct ggml_tensor * Vcur = ggml_cont ( ctx , ggml_view_2d ( ctx , cur , hp . n_embd_gqa (), hp . n_tokens , cur -> nb [ 1 ], 1 * sizeof (float) * ( hp . n_embd + hp . n_embd_gqa ()))); 8762 8763Qcur = ggml_reshape_3d ( ctx , Qcur , hp . n_embd_head , hp . n_head , hp . n_tokens ); 8764Kcur = ggml_reshape_3d ( ctx , Kcur , hp . n_embd_head , hp . n_head_kv , hp . n_tokens ); 8765 8766// using mode = 2 for neox mode 8767Qcur = ggml_rope_ext ( 8768ctx , Qcur , inp_pos , nullptr , hp . n_rot , 2 , hp . n_ctx_orig , 8769freq_base , freq_scale , ext_factor , attn_factor , beta_fast , beta_slow 8770); 8771 8772Kcur = ggml_rope_ext ( 8773ctx , Kcur , inp_pos , nullptr , hp . n_rot , 2 , hp . n_ctx_orig , 8774freq_base , freq_scale , ext_factor , attn_factor , beta_fast , beta_slow 8775); 8776 8777llm_build_kv_store ( ctx , k_l , v_l , Kcur , Vcur ); 8778 8779cur = llm_build_kqv ( ctx , k_l , v_l , Qcur , KQ_mask , 1.0f / sqrtf (float( hp . n_embd_head ))); 8780} 8781 8782struct ggml_tensor * ffn_inp = cur ; 8783 8784// feed forward 8785{ 8786ggml_tensor * ffn_up = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_embd , hp . n_ff ); 8787ggml_tensor * ffn_down = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q4_0 , hp . n_ff , hp . n_embd ); 8788cur = attn_norm ; 8789cur = ggml_mul_mat ( ctx , ffn_up , cur ); 8790cur = ggml_gelu ( ctx , cur ); 8791cur = ggml_mul_mat ( ctx , ffn_down , cur ); 8792} 8793 8794cur = ggml_add ( ctx , cur , ffn_inp ); 8795 8796cur = ggml_add ( ctx , cur , inpL ); 8797 8798// input for next layer 8799inpL = cur ; 8800} 8801 8802cur = inpL ; 8803 8804ggml_tensor * output_norm = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8805ggml_tensor * output_norm_b = ggml_new_tensor_1d ( ctx , GGML_TYPE_F32 , hp . n_embd ); 8806cur = llm_build_norm ( ctx , cur , output_norm , output_norm_b , LLM_NORM ); 8807 8808// lm_head 8809ggml_tensor * output = ggml_new_tensor_2d ( ctx , GGML_TYPE_Q8_0 , hp . n_embd , hp . n_vocab ); 8810cur = ggml_mul_mat ( ctx , output , cur ); 8811 8812return cur ; 8813} 8814}; 8815 8816 8817// ########################################### 8818// ## Section 3: GGML Op Test Instantiation ## 8819// ########################################### 8820static const ggml_type all_types [] = { 8821GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 , 8822GGML_TYPE_Q4_0 , GGML_TYPE_Q4_1 , 8823GGML_TYPE_Q5_0 , GGML_TYPE_Q5_1 , 8824GGML_TYPE_Q8_0 , 8825GGML_TYPE_Q1_0 , 8826GGML_TYPE_Q2_0 , 8827GGML_TYPE_MXFP4 , GGML_TYPE_NVFP4 , 8828GGML_TYPE_Q2_K , GGML_TYPE_Q3_K , 8829GGML_TYPE_Q4_K , GGML_TYPE_Q5_K , 8830GGML_TYPE_Q6_K , 8831GGML_TYPE_TQ2_0 , 8832GGML_TYPE_TQ1_0 , 8833GGML_TYPE_IQ2_XXS , GGML_TYPE_IQ2_XS , GGML_TYPE_IQ2_S , 8834GGML_TYPE_IQ3_XXS , GGML_TYPE_IQ1_S , GGML_TYPE_IQ1_M , 8835GGML_TYPE_IQ4_NL , GGML_TYPE_IQ3_S , GGML_TYPE_IQ4_XS , 8836}; 8837 8838static const ggml_type base_types [] = { 8839GGML_TYPE_F32 , GGML_TYPE_F16 , 8840GGML_TYPE_Q8_0 , // for I8MM tests 8841GGML_TYPE_Q1_0 , 8842GGML_TYPE_Q2_0 , 8843GGML_TYPE_Q4_0 , 8844GGML_TYPE_Q4_1 , // for I8MM tests 8845GGML_TYPE_Q4_K , 8846GGML_TYPE_MXFP4 , GGML_TYPE_NVFP4 , // TODO: or "other" 8847GGML_TYPE_IQ2_XXS 8848}; 8849 8850static const ggml_type other_types [] = { 8851GGML_TYPE_Q4_1 , 8852GGML_TYPE_Q5_0 , GGML_TYPE_Q5_1 , 8853GGML_TYPE_Q8_0 , 8854GGML_TYPE_Q1_0 , 8855GGML_TYPE_Q2_0 , 8856GGML_TYPE_Q2_K , GGML_TYPE_Q3_K , 8857GGML_TYPE_Q5_K , 8858GGML_TYPE_Q6_K , 8859GGML_TYPE_TQ2_0 , 8860GGML_TYPE_TQ1_0 , 8861GGML_TYPE_IQ2_XS , GGML_TYPE_IQ2_S , 8862GGML_TYPE_IQ3_XXS , GGML_TYPE_IQ1_S , GGML_TYPE_IQ1_M , 8863GGML_TYPE_IQ4_NL , GGML_TYPE_IQ3_S , GGML_TYPE_IQ4_XS , 8864GGML_TYPE_BF16 , 8865}; 8866 8867#ifdef _MSC_VER 8868// Workaround long compile time with msvc 8869#pragma optimize("", off) 8870#endif 8871 8872// Test cases for evaluation: should try to cover edge cases while using small input sizes to keep the runtime low 8873static std::vector < std::unique_ptr < test_case >> make_test_cases_eval () { 8874std::vector < std::unique_ptr < test_case >> test_cases ; 8875std::default_random_engine rng ( 0 ); 8876 8877// unary ops 8878for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 8879for (int v : { 0 , 1 }) { 8880for (int op = 0 ; op < GGML_UNARY_OP_COUNT ; op ++ ) { 8881if ( op == GGML_UNARY_OP_XIELU ) { 8882continue ; // need extra params, separate test 8883} 8884test_cases . emplace_back ( new test_unary((ggml_unary_op) op , type , { 128 , 2 , 2 , 2 }, v )); 8885test_cases . emplace_back ( new test_unary((ggml_unary_op) op , type , { 5 , 7 , 11 , 13 }, v )); 8886} 8887} 8888} 8889 8890// fused relu + sqr (squared ReLU) 8891for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 8892test_cases . emplace_back ( new test_relu_sqr( type , { 128 , 2 , 2 , 2 })); 8893test_cases . emplace_back ( new test_relu_sqr( type , { 5 , 7 , 11 , 13 })); 8894} 8895 8896// fused unary + mul (gated activations that are not expressed as GGML_OP_GLU) 8897for (ggml_unary_op op : { GGML_UNARY_OP_GELU , GGML_UNARY_OP_SILU , GGML_UNARY_OP_SIGMOID , GGML_UNARY_OP_SOFTPLUS }) { 8898for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 8899for (bool swap : { false, true }) { 8900test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, swap )); 8901} 8902test_cases . emplace_back ( new test_unary_mul( op , type , { 5 , 7 , 11 , 13 })); 8903test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "pad_unary" )); 8904// a view only stays out from between the two ops when the unary result is second 8905test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, true, "pad_other" )); 8906test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, true, "halves" )); 8907test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "packed" , "consumer" )); 8908test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "bcast" )); 8909test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "rep_ne0" )); 8910test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "view_mid" )); 8911test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "gate" )); 8912// must not fuse 8913test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "strided_dim1" )); 8914test_cases . emplace_back ( new test_unary_mul( op , type , { 128 , 2 , 2 , 2 }, false, "packed" , "reuse" )); 8915} 8916} 8917 8918// SNAKE activation fusion: x + sin(a*x)^2 * inv_b 8919for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 }) { 8920test_cases . emplace_back ( new test_snake_fuse( type , { 5 , 7 , 1 , 1 })); // primes sub-block 8921test_cases . emplace_back ( new test_snake_fuse( type , { 33 , 32 , 1 , 1 })); // boundary 8922test_cases . emplace_back ( new test_snake_fuse( type , { 1025 , 13 , 1 , 1 })); // large prime, grid-stride 8923test_cases . emplace_back ( new test_snake_fuse( type , { 128 , 16 , 1 , 1 })); // power-of-two 8924test_cases . emplace_back ( new test_snake_fuse( type , { 256 , 192 , 1 , 1 })); // BigVGAN-ish 8925// higher-rank shapes: matcher must reject fusion, fallback to naive chain 8926test_cases . emplace_back ( new test_snake_fuse( type , { 64 , 32 , 2 , 1 })); // ne[2] > 1 8927test_cases . emplace_back ( new test_snake_fuse( type , { 64 , 32 , 1 , 2 })); // ne[3] > 1 8928test_cases . emplace_back ( new test_snake_fuse( type , { 64 , 32 , 2 , 3 })); // ne[2] > 1 and ne[3] > 1 8929} 8930 8931test_cases . emplace_back ( new test_dsv4_hc_comb( 1 , 1 )); 8932test_cases . emplace_back ( new test_dsv4_hc_comb( 17 , 4 )); 8933test_cases . emplace_back ( new test_dsv4_hc_comb( 257 , 8 )); 8934test_cases . emplace_back ( new test_dsv4_hc_comb( 17 , 20 )); 8935// production n_iter (DeepSeek-V4 uses 20) across batch sizes that cross 8936// subgroup and workgroup boundaries; 1 = single-token decode 8937for (int64_t n_tokens : { 1 , 256 , 336 , 512 , 513 , 1024 , 2048 }) { 8938test_cases . emplace_back ( new test_dsv4_hc_comb( n_tokens , 20 )); 8939} 8940 8941test_cases . emplace_back ( new test_dsv4_hc_pre( 1 , 1 )); 8942test_cases . emplace_back ( new test_dsv4_hc_pre( 31 , 17 )); 8943test_cases . emplace_back ( new test_dsv4_hc_pre( 128 , 257 )); 8944test_cases . emplace_back ( new test_dsv4_hc_pre( 4096 , 21 )); 8945 8946test_cases . emplace_back ( new test_dsv4_hc_post( 1 , 1 )); 8947test_cases . emplace_back ( new test_dsv4_hc_post( 31 , 17 )); 8948test_cases . emplace_back ( new test_dsv4_hc_post( 128 , 257 )); 8949test_cases . emplace_back ( new test_dsv4_hc_post( 4096 , 21 )); 8950 8951// glu ops 8952for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 8953for (int v : { 0 , 1 }) { 8954for (int op = 0 ; op < GGML_GLU_OP_COUNT ; op ++ ) { 8955if ( op == GGML_GLU_OP_SWIGLU_OAI || op == GGML_GLU_OP_SWIGLU_CLAMP ) { 8956continue ; 8957} 8958 8959for (bool swapped : {false, true}) { 8960test_cases . emplace_back ( new test_glu((ggml_glu_op) op , type , { 128 , 2 , 2 , 2 }, v , swapped )); 8961test_cases . emplace_back ( new test_glu((ggml_glu_op) op , type , { 5 , 7 , 11 , 13 }, v , swapped )); 8962} 8963 8964test_cases . emplace_back ( new test_glu_split((ggml_glu_op) op , type , { 128 , 2 , 2 , 2 }, v )); 8965test_cases . emplace_back ( new test_glu_split((ggml_glu_op) op , type , { 5 , 7 , 11 , 13 }, v )); 8966} 8967} 8968} 8969 8970for (int v : { 0 , 1 }) { 8971for (float alpha : { .5f , 1.702f }) { 8972for (float limit : { 2.0f , 7.0f }) { 8973test_cases . emplace_back ( new test_swiglu_oai( GGML_TYPE_F32 , { 128 , 2 , 2 , 2 }, v , alpha , limit )); 8974} 8975} 8976} 8977 8978for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 8979for (int v : { 0 , 1 }) { 8980for (float limit : { 2.0f , 10.0f }) { 8981test_cases . emplace_back ( new test_swiglu_clamp( type , { 128 , 2 , 2 , 2 }, v , limit )); 8982} 8983} 8984} 8985 8986for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_Q4_0 }) { 8987test_cases . emplace_back ( new test_get_rows( type , 300 * 256 , 5 , 4 , 1 , 2 , false)); 8988test_cases . emplace_back ( new test_get_rows( type , 256 , 80000 , 70000 , 2 , 1 , false)); 8989test_cases . emplace_back ( new test_get_rows( type , 256 , 5 , 4 , 700 , 100 , false)); 8990} 8991 8992test_cases . emplace_back ( new test_get_rows( GGML_TYPE_F32 , 1 , 8 , 2 , 1 , 1 , false)); 8993for (ggml_type type : all_types ) { 8994for (int b : { 1 , 7 }) { 8995for (bool v : {false, true}) { 8996for (bool vs0 : {false, true}) { 8997test_cases . emplace_back ( new test_get_rows( type , 256 , 5 , 4 , b , 1 , v , vs0 )); 8998} 8999} 9000} 9001} 9002for (int b : { 1 , 7 }) { 9003for (bool v : {false, true}) { 9004for (bool vs0 : {false, true}) { 9005test_cases . emplace_back ( new test_get_rows( GGML_TYPE_I32 , 256 , 5 , 4 , b , 1 , v , vs0 )); 9006} 9007} 9008} 9009 9010test_cases . emplace_back ( new test_get_rows_back( GGML_TYPE_F32 , 1 , 8 , 2 , 1 , false)); 9011test_cases . emplace_back ( new test_get_rows_back( GGML_TYPE_F32 , 1 , 70000 , 4 , 1 , false)); // row count > CUDA grid-y limit (65535) 9012for (ggml_type type : all_types ) { 9013for (bool v : {false, true}) { 9014test_cases . emplace_back ( new test_get_rows_back( type , 256 , 5 , 4 , 1 , v )); 9015} 9016} 9017for (bool v : {false, true}) { 9018test_cases . emplace_back ( new test_get_rows_back( GGML_TYPE_I32 , 256 , 5 , 4 , 1 , v )); 9019} 9020 9021test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_I64 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , false)); 9022test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_I32 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , false)); 9023test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_I32 , { 256 , 5 , 1 , 3 }, { 1 , 1 , }, 1 , false)); 9024for (ggml_type src_type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 9025for (ggml_type type : all_types ) { 9026for (int b : { 1 , 7 }) { 9027for (bool v : {false, true}) { 9028test_cases . emplace_back ( new test_set_rows( src_type , type , GGML_TYPE_I64 , { 256 , 5 , b , 3 }, { 1 , 1 , }, 1 , v )); 9029test_cases . emplace_back ( new test_set_rows( src_type , type , GGML_TYPE_I64 , { 256 , 11 , 1 , b }, { 2 , 3 , }, 7 , v )); 9030 9031test_cases . emplace_back ( new test_set_rows( src_type , type , GGML_TYPE_I64 , { 3 * ggml_blck_size ( type ), 3 , b , 1 }, { 2 , 3 , }, 2 , v )); 9032 9033if ( ggml_blck_size ( type ) == 1 ) { 9034test_cases . emplace_back ( new test_set_rows( src_type , type , GGML_TYPE_I64 , { 31 , 3 , b , 1 }, { 2 , 3 , }, 2 , v )); 9035test_cases . emplace_back ( new test_set_rows( src_type , type , GGML_TYPE_I64 , { 33 , 5 , 1 , b }, { 2 , 3 , }, 1 , v )); 9036} 9037} 9038} 9039} 9040} 9041test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F16 , GGML_TYPE_F16 , GGML_TYPE_I64 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , false)); 9042test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F16 , GGML_TYPE_F16 , GGML_TYPE_I32 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , false)); 9043test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F16 , GGML_TYPE_F16 , GGML_TYPE_I64 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , true)); 9044test_cases . emplace_back ( new test_set_rows( GGML_TYPE_F16 , GGML_TYPE_F16 , GGML_TYPE_I32 , { 1 , 8 , 1 , 3 }, { 1 , 1 }, 2 , true)); 9045 9046for (int mode : { GGML_ROPE_TYPE_NORMAL , GGML_ROPE_TYPE_NEOX , GGML_ROPE_TYPE_MROPE , GGML_ROPE_TYPE_VISION , GGML_ROPE_TYPE_IMROPE }) { 9047for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 9048for (int ne2 : { 1 , 8 , 512 }) { 9049test_cases . emplace_back ( new test_rope_set_rows( type , GGML_TYPE_I64 , { 128 , 32 , ne2 , 1 }, mode )); 9050test_cases . emplace_back ( new test_rope_set_rows( type , GGML_TYPE_I64 , { 128 , 32 , ne2 , 3 }, mode )); 9051} 9052} 9053} 9054test_cases . emplace_back ( new test_rope_set_rows( GGML_TYPE_F32 , GGML_TYPE_I32 , { 128 , 32 , 8 , 1 }, GGML_ROPE_TYPE_IMROPE )); 9055 9056for (ggml_type type_input : { GGML_TYPE_F32 }) { 9057for (ggml_op_pool pool_type : { GGML_OP_POOL_AVG , GGML_OP_POOL_MAX }) { 9058for (int k0 : { 1 , 3 }) { 9059for (int k1 : { 1 , 3 }) { 9060for (int s0 : { 1 , 2 }) { 9061for (int s1 : { 1 , 2 }) { 9062for (int p0 : { 0 , 1 }) { 9063for (int p1 : { 0 , 1 }) { 9064test_cases . emplace_back ( new test_pool2d( pool_type , type_input , { 10 , 10 , 3 , 1 }, k0 , k1 , s0 , s1 , p0 , p1 )); 9065} 9066} 9067} 9068} 9069} 9070} 9071} 9072} 9073 9074for (ggml_type type_input : { GGML_TYPE_F32 }) { 9075for (ggml_op_pool pool_type : { GGML_OP_POOL_AVG , GGML_OP_POOL_MAX }) { 9076for (int k0 : { 1 , 2 , 3 }) { 9077for (int s0 : { 1 , 2 , 3 }) { 9078for (int p0 : { 0 , 1 , 2 , 3 }) { 9079test_cases . emplace_back ( new test_pool1d( pool_type , type_input , { 10 , 3 , 2 , 1 }, k0 , s0 , p0 )); 9080test_cases . emplace_back ( new test_pool1d( pool_type , type_input , { 11 , 1 , 3 , 2 }, k0 , s0 , p0 )); 9081test_cases . emplace_back ( new test_pool1d( pool_type , type_input , { 128 , 2 , 1 , 3 }, k0 , s0 , p0 )); 9082} 9083} 9084} 9085} 9086} 9087 9088#if 0 9089// >4GB im2col destination. Too slow to run by default. 9090// Test cases taken from Wan2.1 T2V 1.3B. 9091test_cases . emplace_back ( new test_im2col ( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 832 , 480 , 192 , 4 }, { 3 , 3 , 192 , 96 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9092test_cases . emplace_back ( new test_im2col_3d( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 834 , 482 , 6 , 96 }, { 3 , 3 , 3 , 9216 }, 96 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , false)); 9093#endif 9094 9095// im2col 1D 9096test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 3000 , 128 , 1 , 1 }, { 3 , 128 , 1280 , 1 }, 1 , 0 , 1 , 0 , 1 , 0 , false)); 9097test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F32 , { 3000 , 128 , 1 , 1 }, { 3 , 128 , 1280 , 1 }, 1 , 0 , 1 , 0 , 1 , 0 , false)); 9098test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 3000 , 128 , 1 , 1 }, { 3 , 128 , 1280 , 1 }, 1 , 0 , 1 , 0 , 1 , 0 , false)); 9099test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 3000 , 384 , 1 , 1 }, { 3 , 384 , 384 , 1 }, 1 , 0 , 1 , 0 , 1 , 0 , false)); 9100for (int s0 : { 1 , 3 }) { 9101for (int p0 : { 0 , 3 }) { 9102for (int d0 : { 1 , 3 }) { 9103test_cases . emplace_back ( new test_im2col( 9104GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 20 , 2 , 2 , 1 }, { 3 , 2 , 2 , 1 }, 9105s0 , 0 , p0 , 0 , d0 , 0 , false)); 9106} 9107} 9108} 9109 9110// im2col 2D 9111test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 )); 9112test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F16 )); 9113test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F32 )); 9114test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 9115for (int s0 : { 1 , 3 }) { 9116for (int s1 : { 1 , 3 }) { 9117for (int p0 : { 0 , 3 }) { 9118for (int p1 : { 0 , 3 }) { 9119for (int d0 : { 1 , 3 }) { 9120for (int d1 : { 1 , 3 }) { 9121test_cases . emplace_back ( new test_im2col( 9122GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 20 , 20 , 2 , 2 }, { 3 , 3 , 2 , 2 }, 9123s0 , s1 , p0 , p1 , d0 , d1 , true)); 9124} 9125} 9126} 9127} 9128} 9129} 9130 9131// extra tests for im2col 2D 9132test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 1 , 32 }, { 3 , 3 , 1 , 32 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9133test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 2 , 32 }, { 3 , 3 , 2 , 32 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9134test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 1 , 1024 }, { 3 , 3 , 1 , 1024 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9135test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 2 , 1024 }, { 3 , 3 , 2 , 1024 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9136test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 1 , 2048 }, { 3 , 3 , 1 , 2048 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9137test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 2 , 2048 }, { 3 , 3 , 2 , 2048 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9138test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 1 , 2560 }, { 3 , 3 , 1 , 2560 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9139test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 12 , 12 , 2 , 2560 }, { 3 , 3 , 2 , 2560 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9140test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 5 , 5 , 1 , 32 }, { 3 , 4 , 1 , 32 }, 1 , 1 , 0 , 0 , 1 , 1 , true)); 9141test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 2 , 2 , 1536 , 729 }, { 2 , 2 , 1536 , 4096 }, 1 , 1 , 0 , 0 , 1 , 1 , true)); 9142test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 128 , 128 , 1 , 2 }, { 32 , 33 , 1 , 2 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9143test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 128 , 128 , 2 , 1 }, { 33 , 34 , 2 , 1 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 9144 9145// im2col 3D 9146test_cases . emplace_back ( new test_im2col_3d( GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 )); 9147test_cases . emplace_back ( new test_im2col_3d( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F32 )); 9148test_cases . emplace_back ( new test_im2col_3d( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 9149for (int s0 : { 1 , 3 }) { 9150for (int s1 : { 1 , 3 }) { 9151for (int s2 : { 1 , 3 }) { 9152for (int p0 : { 0 , 3 }) { 9153for (int p1 : { 0 , 3 }) { 9154for (int p2 : { 0 , 3 }) { 9155for (int d0 : { 1 , 3 }) { 9156for (int d1 : { 1 , 3 }) { 9157for (int d2 : { 1 , 3 }) { 9158for (int IC : { 1 , 3 }) { 9159for (bool v : {false, true}) { 9160test_cases . emplace_back ( new test_im2col_3d( 9161GGML_TYPE_F32 , GGML_TYPE_F32 , GGML_TYPE_F32 , { 20 , 20 , 10 , 3 }, { 3 , 3 , 3 , 3 }, 9162IC , s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 , v )); 9163} 9164} 9165} 9166} 9167} 9168} 9169} 9170} 9171} 9172} 9173} 9174 9175// Conv_2D test cases 9176#ifdef DETAILED_TESTS 9177// Probably we do not have enough time to execute these in the pipeline. 9178uint32_t iwh_idx = 0 ; 9179uint32_t kwh_idx = 1 ; 9180uint32_t Cout_idx = 2 ; 9181uint32_t Cin_idx = 3 ; 9182uint32_t B_idx = 4 ; 9183 9184std::vector < std::array < int, 5 >> cases = { 9185//{IWH, KWH, Cout, Cin, B} 9186// K=CRS=NPQ=4096 conv_2d matmul performance 9187{ 19 , 4 , 4096 , 256 , 16 }, 9188// K=128, CRS=128, NPQ=4096 9189{ 19 , 4 , 128 , 8 , 16 }, 9190// K=130, CRS=128, NPQ=4096 9191{ 19 , 4 , 130 , 8 , 16 }, 9192// Edge case: K x CRS is small 9193{ 19 , 2 , 4 , 4 , 16 }, 9194// A ConvNet's first layer 9195{ 224 , 3 , 8 , 3 , 1 }, 9196// A ConvNet's first layer with 2x2 convolution, and 1 channel 9197{ 224 , 2 , 8 , 1 , 1 }, 9198// A ConvNet's first layer with 2x2 convolution, and 1 channel, several images in the batch 9199{ 224 , 2 , 8 , 1 , 8 }, 9200// A middle layer of a ConvNet 9201{ 58 , 3 , 64 , 32 , 1 }, 9202// A middle layer of a ConvNet, several images in the batch 9203{ 58 , 3 , 64 , 32 , 8 }, 9204// A deep layer of a ConvNet, several images in the batch 9205{ 16 , 3 , 256 , 128 , 8 } 9206}; 9207 9208for (auto kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9209for (auto act_case : cases ) { 9210test_cases . emplace_back ( new test_conv_2d( 9211{ act_case [ iwh_idx ], act_case [ iwh_idx ], act_case [ Cin_idx ], act_case [ B_idx ] }, 9212{ act_case [ kwh_idx ], act_case [ kwh_idx ], act_case [ Cin_idx ], act_case [ Cout_idx ] }, 9213kernel_type , 1 , 1 , 0 , 0 , 1 , 1 , false)); // bool cwhn = false 9214test_cases . emplace_back ( new test_conv_2d( 9215{ act_case [ iwh_idx ], act_case [ iwh_idx ], act_case [ Cin_idx ], act_case [ B_idx ] }, 9216{ act_case [ kwh_idx ], act_case [ kwh_idx ], act_case [ Cin_idx ], act_case [ Cout_idx ] }, 9217kernel_type , 1 , 1 , 0 , 0 , 1 , 1 , true)); // bool cwhn = true 9218} 9219} 9220#endif 9221 9222// CONV_2D: 9223auto calc_conv_output_size = [](int64_t ins , int64_t ks , int s , int p , int d ) -> int64_t { 9224return ( ins + 2 * p - d * ( ks - 1 ) - 1 ) / s + 1 ; 9225}; 9226 9227//uint32_t s0 = 3; 9228uint32_t s1 = 5 ; 9229uint32_t p0 = 5 ; 9230//uint32_t p1 = 2; 9231uint32_t d0 = 2 ; 9232uint32_t d1 = 4 ; 9233 9234for (uint32_t s0 : { 1 , 3 }) { 9235for (uint32_t p1 : { 2 , 5 }) { 9236for (uint32_t Cin : { 1 , 25 }) { 9237for (uint32_t Cout : { 1 , 12 }) { 9238for (uint32_t KH : { 1 , 2 , 3 , 11 }) { 9239for (uint32_t KW : { 1 , 2 , 3 , 11 }) { 9240for (uint32_t H : { 1 , 133 }) { 9241for (uint32_t W : { 1 , 141 }) { 9242if ( calc_conv_output_size ( W , KW , s0 , p0 , d0 ) > 0 && 9243calc_conv_output_size ( H , KH , s1 , p1 , d1 ) > 0 ) { 9244for (auto kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9245test_cases . emplace_back ( new test_conv_2d( 9246{ W , H , Cin , 2 }, { KW , KH , Cin , Cout }, kernel_type , s0 , s1 , p0 , p1 , d0 , d1 , false)); // bool cwhn = false 9247test_cases . emplace_back ( new test_conv_2d( 9248{ W , H , Cin , 2 }, { KW , KH , Cin , Cout }, kernel_type , s0 , s1 , p0 , p1 , d0 , d1 , true)); // bool cwhn = true 9249} 9250} 9251} 9252} 9253} 9254} 9255} 9256} 9257} 9258} 9259for (auto kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9260test_cases . emplace_back ( new test_conv_2d({ 256 , 256 , 192 , 1 }, { 3 , 3 , 192 , 96 }, kernel_type , 1 , 1 , 1 , 1 , 1 , 1 , false)); // bool cwhn = false 9261test_cases . emplace_back ( new test_conv_2d({ 256 , 256 , 192 , 1 }, { 3 , 3 , 192 , 96 }, kernel_type , 1 , 1 , 1 , 1 , 1 , 1 , true)); // bool cwhn = true 9262} 9263 9264// sycl backend will limit task global_range < MAX_INT 9265// test cases for 2D im2col with large input W and H (occurs in stable-diffusion) 9266// however these cases need to alloc more memory which may fail in some devices (Intel Arc770, etc.) 9267// these cases are verified (pass) in Intel(R) Data Center GPU Max 1100 (sycl backend) and NV A30 (cuda backend) 9268// test_cases.emplace_back(new test_im2col(GGML_TYPE_F32, GGML_TYPE_F16, GGML_TYPE_F16, {1024, 1024, 256, 1}, {3, 3, 256, 1}, 1, 1, 1, 1, 1, 1, true)); 9269// test_cases.emplace_back(new test_im2col(GGML_TYPE_F32, GGML_TYPE_F16, GGML_TYPE_F32, {1024, 1024, 256, 1}, {3, 3, 256, 1}, 1, 1, 1, 1, 1, 1, true)); 9270 9271test_cases . emplace_back ( new test_conv_2d_dw({ 17 , 34 , 9 , 1 }, { 3 , 3 , 1 , 9 }, GGML_TYPE_F32 , 1 , 0 , 1 , false)); 9272test_cases . emplace_back ( new test_conv_2d_dw({ 17 , 34 , 9 , 1 }, { 3 , 3 , 1 , 9 }, GGML_TYPE_F32 , 1 , 0 , 1 , true)); 9273test_cases . emplace_back ( new test_conv_2d_dw({ 32 , 8 , 64 , 1 }, { 3 , 3 , 1 , 64 }, GGML_TYPE_F32 , 2 , 1 , 1 , false)); 9274test_cases . emplace_back ( new test_conv_2d_dw({ 32 , 8 , 64 , 1 }, { 3 , 3 , 1 , 64 }, GGML_TYPE_F32 , 2 , 1 , 1 , true)); 9275 9276test_cases . emplace_back ( new test_conv_2d_dw({ 17 , 34 , 9 , 1 }, { 3 , 3 , 1 , 9 }, GGML_TYPE_F16 , 1 , 0 , 1 , false)); 9277test_cases . emplace_back ( new test_conv_2d_dw({ 17 , 34 , 9 , 1 }, { 3 , 3 , 1 , 9 }, GGML_TYPE_F16 , 1 , 0 , 1 , true)); 9278test_cases . emplace_back ( new test_conv_2d_dw({ 32 , 8 , 64 , 1 }, { 3 , 3 , 1 , 64 }, GGML_TYPE_F16 , 2 , 1 , 1 , false)); 9279test_cases . emplace_back ( new test_conv_2d_dw({ 32 , 8 , 64 , 1 }, { 3 , 3 , 1 , 64 }, GGML_TYPE_F16 , 2 , 1 , 1 , true)); 9280 9281// CONV_3D 9282auto calc_conv_output_size_3d = [](int64_t ins , int64_t ks , int s , int p , int d ) -> int64_t { 9283return ( ins + 2 * p - d * ( ks - 1 ) - 1 ) / s + 1 ; 9284}; 9285 9286for (ggml_type kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9287for (int N : { 1 , 2 }) { 9288for (int IC : { 1 , 3 }) { 9289for (int OC : { 1 , 4 }) { 9290for (int s0 : { 1 , 2 }) { 9291for (int p1 : { 0 , 1 }) { 9292for (int d2 : { 1 , 2 }) { 9293int64_t IW = 20 , IH = 22 , ID = 18 ; 9294int64_t KW = 3 , KH = 3 , KD = 3 ; 9295int s1 = s0 , s2 = s0 ; 9296int p0 = p1 , p2 = p1 ; 9297int d0 = d2 , d1 = d2 ; 9298 9299if ( calc_conv_output_size_3d ( IW , KW , s0 , p0 , d0 ) <= 0 || 9300calc_conv_output_size_3d ( IH , KH , s1 , p1 , d1 ) <= 0 || 9301calc_conv_output_size_3d ( ID , KD , s2 , p2 , d2 ) <= 0 ) { 9302continue ; 9303} 9304test_cases . emplace_back ( new test_conv_3d( 9305N , IC , ID , IH , IW , 9306OC , KD , KH , KW , 9307s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 , 9308kernel_type )); 9309 9310// Asymmetric kernel and params 9311int64_t asym_KW = 5 , asym_KH = 1 , asym_KD = 3 ; 9312int asym_s0 = 2 , asym_s1 = 1 , asym_s2 = 1 ; 9313int asym_p0 = 2 , asym_p1 = 0 , asym_p2 = 1 ; 9314int asym_d0 = 1 , asym_d1 = 1 , asym_d2 = 2 ; 9315 9316if ( calc_conv_output_size_3d ( IW , asym_KW , asym_s0 , asym_p0 , asym_d0 ) <= 0 || 9317calc_conv_output_size_3d ( IH , asym_KH , asym_s1 , asym_p1 , asym_d1 ) <= 0 || 9318calc_conv_output_size_3d ( ID , asym_KD , asym_s2 , asym_p2 , asym_d2 ) <= 0 ) { 9319continue ; 9320} 9321test_cases . emplace_back ( new test_conv_3d( 9322N , IC , ID , IH , IW , 9323OC , asym_KD , asym_KH , asym_KW , 9324asym_s0 , asym_s1 , asym_s2 , asym_p0 , asym_p1 , asym_p2 , asym_d0 , asym_d1 , asym_d2 , 9325kernel_type )); 9326} 9327} 9328} 9329} 9330} 9331} 9332// Case with kernel size 1 9333test_cases . emplace_back ( new test_conv_3d( 1 , 4 , 8 , 8 , 8 , 8 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , kernel_type )); 9334} 9335 9336for (uint32_t Cout : { 1 , 9 }){ 9337for (uint32_t Cin : { 1 , 7 }){ 9338for (uint32_t K : { 1 , 3 , 1337 }){ 9339for (uint32_t L : { 1 , 2 , 13 }){ 9340for (uint32_t s0 : { 1 , 2 , 3 }){ 9341test_cases . emplace_back ( new test_conv_transpose_1d({ L , Cin , 1 , 1 }, { K , Cout , Cin , 1 }, s0 , 0 , 1 )); 9342} 9343} 9344} 9345} 9346} 9347 9348test_cases . emplace_back ( new test_conv_transpose_1d()); 9349test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 2 , 3 , 2 , 1 }, 3 , 0 , 1 )); 9350test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 2 , 3 , 2 , 1 }, 2 , 0 , 1 )); 9351test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 2 , 3 , 2 , 1 }, 1 , 0 , 1 )); 9352test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 3 , 2 , 2 , 1 }, 2 , 0 , 1 )); 9353test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 3 , 2 , 2 , 1 }, 1 , 0 , 1 )); 9354test_cases . emplace_back ( new test_conv_transpose_1d({ 3 , 2 , 1 , 1 }, { 3 , 1 , 2 , 1 }, 1 , 0 , 1 )); 9355test_cases . emplace_back ( new test_conv_transpose_1d({ 2 , 1 , 1 , 1 }, { 3 , 1 , 1 , 1 }, 1 , 0 , 1 )); 9356 9357for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 }) { 9358// ConvTranspose1d expressed as mul_mat + col2im (DAC decoder upsampling) 9359test_cases . emplace_back ( new test_col2im_1d( type , 16 , 32 , 197 , 8 , 0 )); // kernel = 2*stride 9360test_cases . emplace_back ( new test_col2im_1d( type , 4 , 3 , 7 , 2 , 0 )); 9361test_cases . emplace_back ( new test_col2im_1d( type , 1 , 5 , 13 , 1 , 0 )); // stride 1, no overlap 9362test_cases . emplace_back ( new test_col2im_1d( type , 6 , 4 , 11 , 3 , 1 )); // with cropping 9363test_cases . emplace_back ( new test_col2im_1d( type , 2 , 3 , 9 , 3 , 0 )); // kernel < stride, gap positions are zeroed 9364test_cases . emplace_back ( new test_col2im_1d( type , 5 , 4 , 11 , 2 , 0 )); // kernel not a multiple of stride, alternating overlap 9365test_cases . emplace_back ( new test_col2im_1d( type , 8 , 4 , 13 , 4 , 2 )); // padding = stride/2 (DAC causal cropping) 9366test_cases . emplace_back ( new test_col2im_1d( type , 4 , 3 , 1 , 2 , 0 )); // single column, pure kernel unfold 9367test_cases . emplace_back ( new test_col2im_1d( type , 16 , 1 , 197 , 8 , 0 )); // OC = 1, mono output stage 9368test_cases . emplace_back ( new test_col2im_1d( type , 1 , 5 , 13 , 3 , 0 )); // K = 1 with stride > 1, sparse scatter 9369test_cases . emplace_back ( new test_col2im_1d( type , 8 , 2 , 3 , 2 , 5 )); // cropping eats most of the signal, T_out = 2 9370} 9371 9372for (ggml_type kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9373test_cases . emplace_back ( new test_conv_transpose_2d({ 3 , 2 , 3 , 1 }, { 2 , 2 , 1 , 3 }, 1 , kernel_type )); 9374test_cases . emplace_back ( new test_conv_transpose_2d({ 10 , 10 , 9 , 1 }, { 3 , 3 , 1 , 9 }, 2 , kernel_type )); 9375test_cases . emplace_back ( new test_conv_transpose_2d({ 129 , 63 , 35 , 1 }, { 3 , 3 , 48 , 35 }, 1 , kernel_type )); 9376test_cases . emplace_back ( new test_conv_transpose_2d({ 10 , 10 , 9 , 2 }, { 3 , 3 , 1 , 9 }, 2 , kernel_type )); // for multiple batches 9377} 9378 9379test_cases . emplace_back ( new test_count_equal( GGML_TYPE_F32 , { 4 , 500 , 1 , 1 })); 9380test_cases . emplace_back ( new test_count_equal( GGML_TYPE_F32 , { 4 , 5000 , 1 , 1 })); 9381 9382test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 32 , 1 , 1 , 1 })); 9383test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 32 , 513 , 1 , 1 })); 9384test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 100 , 10 , 1 , 1 })); 9385test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 1024 , 10 , 1 , 1 })); 9386test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 1024 , 12 , 1 , 1 })); 9387test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 2000 , 10 , 1 , 1 })); 9388test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 5438 , 3 , 1 , 1 })); 9389 9390for (int ne3 : { 1 , 3 }) { // CUDA backward pass only supports ne3 == 1 9391test_cases . emplace_back ( new test_repeat( GGML_TYPE_F32 , { 10 , 5 , 4 , ne3 }, { 1 , 1 , 1 , 1 })); 9392test_cases . emplace_back ( new test_repeat( GGML_TYPE_F32 , { 10 , 5 , 4 , ne3 }, { 2 , 1 , 1 , 1 })); 9393test_cases . emplace_back ( new test_repeat( GGML_TYPE_F32 , { 10 , 5 , 4 , ne3 }, { 1 , 2 , 1 , 1 })); 9394test_cases . emplace_back ( new test_repeat( GGML_TYPE_F32 , { 10 , 5 , 4 , ne3 }, { 1 , 1 , 2 , 1 })); 9395test_cases . emplace_back ( new test_repeat( GGML_TYPE_F32 , { 10 , 5 , 4 , ne3 }, { 1 , 1 , 1 , 2 })); 9396test_cases . emplace_back ( new test_repeat( GGML_TYPE_F16 , { 10 , 5 , 4 , ne3 }, { 2 , 1 , 1 , 1 })); 9397test_cases . emplace_back ( new test_repeat( GGML_TYPE_I32 , { 10 , 5 , 4 , ne3 }, { 2 , 1 , 1 , 1 })); 9398test_cases . emplace_back ( new test_repeat( GGML_TYPE_I16 , { 10 , 5 , 4 , ne3 }, { 1 , 1 , 1 , 2 })); 9399test_cases . emplace_back ( new test_repeat( GGML_TYPE_BF16 , { 10 , 5 , 4 , ne3 }, { 2 , 1 , 1 , 1 })); 9400} 9401 9402for (bool view : {false, true}) { 9403test_cases . emplace_back ( new test_repeat_back( GGML_TYPE_F32 , { 8 , 6 , 4 , 2 }, { 1 , 1 , 1 , 1 }, view )); 9404test_cases . emplace_back ( new test_repeat_back( GGML_TYPE_F32 , { 8 , 6 , 4 , 2 }, { 2 , 1 , 1 , 1 }, view )); 9405test_cases . emplace_back ( new test_repeat_back( GGML_TYPE_F32 , { 8 , 6 , 4 , 2 }, { 1 , 2 , 1 , 1 }, view )); 9406test_cases . emplace_back ( new test_repeat_back( GGML_TYPE_F32 , { 8 , 6 , 4 , 2 }, { 1 , 1 , 2 , 1 }, view )); 9407test_cases . emplace_back ( new test_repeat_back( GGML_TYPE_F32 , { 8 , 6 , 4 , 2 }, { 1 , 1 , 1 , 2 }, view )); 9408} 9409 9410test_cases . emplace_back ( new test_dup( GGML_TYPE_F32 )); 9411test_cases . emplace_back ( new test_dup( GGML_TYPE_F16 )); 9412test_cases . emplace_back ( new test_dup( GGML_TYPE_I32 )); 9413test_cases . emplace_back ( new test_dup( GGML_TYPE_I16 )); 9414test_cases . emplace_back ( new test_dup( GGML_TYPE_F32 , { 10 , 10 , 5 , 1 }, { 0 , 2 , 1 , 3 })); 9415test_cases . emplace_back ( new test_dup( GGML_TYPE_F16 , { 10 , 10 , 5 , 1 }, { 0 , 2 , 1 , 3 })); // dup by rows 9416test_cases . emplace_back ( new test_dup( GGML_TYPE_F32 , { 10 , 10 , 5 , 1 }, { 1 , 0 , 2 , 3 })); 9417test_cases . emplace_back ( new test_dup( GGML_TYPE_F16 , { 10 , 10 , 5 , 1 }, { 1 , 0 , 2 , 3 })); // dup dst not-contiguous 9418test_cases . emplace_back ( new test_dup( GGML_TYPE_I16 , { 10 , 8 , 3 , 1 }, { 0 , 2 , 1 , 3 })); 9419test_cases . emplace_back ( new test_dup( GGML_TYPE_I16 , { 10 , 8 , 3 , 1 }, { 1 , 2 , 0 , 3 })); 9420 9421for (int dim = 1 ; dim < GGML_MAX_DIMS ; ++ dim ) { 9422test_cases . emplace_back ( new test_set( GGML_TYPE_F32 , GGML_TYPE_F32 , { 6 , 5 , 4 , 3 }, dim , false)); 9423test_cases . emplace_back ( new test_set( GGML_TYPE_F32 , GGML_TYPE_F32 , { 6 , 5 , 4 , 3 }, dim , true)); 9424} 9425 9426for (int dim = 1 ; dim < GGML_MAX_DIMS ; ++ dim ) { 9427test_cases . emplace_back ( new test_set( GGML_TYPE_I32 , GGML_TYPE_I32 , { 6 , 5 , 4 , 3 }, dim , false)); 9428test_cases . emplace_back ( new test_set( GGML_TYPE_I32 , GGML_TYPE_I32 , { 6 , 5 , 4 , 3 }, dim , true)); 9429} 9430 9431// same-type copy 9432for (ggml_type type : all_types ) { 9433const auto nk = ggml_blck_size ( type ); 9434 9435for (int k = 1 ; k < 4 ; ++ k ) { 9436test_cases . emplace_back ( new test_cpy( type , type , { k * nk , 2 , 3 , 4 })); 9437test_cases . emplace_back ( new test_cpy( type , type , { k * nk , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 0 , 2 , 1 , 3 })); 9438test_cases . emplace_back ( new test_cpy( type , type , { k * nk , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 0 , 3 , 1 , 2 }, { 0 , 2 , 1 , 3 })); 9439} 9440} 9441 9442for (ggml_type type_src : { GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_F32 }) { 9443for (ggml_type type_dst : all_types ) { 9444test_cases . emplace_back ( new test_cpy( type_src , type_dst , { 256 , 4 , 4 , 4 })); 9445test_cases . emplace_back ( new test_cpy( type_src , type_dst , { 256 , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 0 , 2 , 1 , 3 })); // cpy by rows 9446} 9447} 9448for (ggml_type type_src : all_types ) { 9449for (ggml_type type_dst : { GGML_TYPE_F32 }) { 9450test_cases . emplace_back ( new test_cpy( type_src , type_dst , { 256 , 4 , 4 , 4 })); 9451test_cases . emplace_back ( new test_cpy( type_src , type_dst , { 256 , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 0 , 2 , 1 , 3 })); // cpy by rows 9452} 9453} 9454for (ggml_type type_src : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 9455for (ggml_type type_dst : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 9456test_cases . emplace_back ( new test_cpy( type_src , type_dst , { 256 , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 })); // cpy not-contiguous 9457} 9458} 9459// quant block count not a multiple of the kernel block size 9460test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_Q4_0 , { 96 , 1 , 1 , 1 })); 9461test_cases . emplace_back ( new test_cpy( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , { 96 , 1 , 1 , 1 })); 9462test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_I32 , { 256 , 2 , 3 , 4 })); 9463test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_I32 , { 256 , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 })); 9464test_cases . emplace_back ( new test_cpy( GGML_TYPE_I32 , GGML_TYPE_F32 , { 256 , 2 , 3 , 4 })); 9465test_cases . emplace_back ( new test_cpy( GGML_TYPE_I32 , GGML_TYPE_F32 , { 256 , 2 , 3 , 4 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 })); 9466test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 256 , 4 , 3 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9467test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 256 , 4 , 3 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9468test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 256 , 4 , 3 , 3 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9469test_cases . emplace_back ( new test_cpy( GGML_TYPE_BF16 , GGML_TYPE_BF16 , { 256 , 4 , 3 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9470test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 256 , 4 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9471test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 256 , 4 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9472test_cases . emplace_back ( new test_cpy( GGML_TYPE_BF16 , GGML_TYPE_BF16 , { 256 , 4 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9473test_cases . emplace_back ( new test_cpy( GGML_TYPE_I32 , GGML_TYPE_I32 , { 256 , 4 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 9474test_cases . emplace_back ( new test_cpy( GGML_TYPE_I32 , GGML_TYPE_I32 , { 256 , 1 , 4 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 2 , 0 , 3 }, { 0 , 0 , 0 , 0 })); 9475test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 256 , 1 , 4 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 2 , 0 , 3 }, { 0 , 0 , 0 , 0 })); 9476test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 2 , 2097121 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 })); 9477test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 2 , 2 , 524281 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 })); 9478test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 128 , 2 , 3 , 1 }, { 128 , 2 , 3 , 1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, false, { 128 , 4 , 3 , 1 })); // strided dst 9479test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 128 , 2 , 3 , 1 }, { 128 , 2 , 3 , 1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, false, { 128 , 4 , 3 , 1 })); // strided dst 9480 9481// CPY - different src/dst shapes (reshaping via CPY) 9482// Use permutations of {3, 5, 7, 32}. Total elements: 3*5*7*32 = 3360. 9483// Each src permutation is tested against canonical sorted and reverse dst (skip self). 9484{ 9485std::array < int64_t, 4 > dims = { 3 , 5 , 7 , 32 }; 9486std:: sort ( dims . begin (), dims . end ()); 9487std::array < int64_t, 4 > canonical = dims ; 9488std::array < int64_t, 4 > reversed = { 32 , 7 , 5 , 3 }; 9489for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9490std::array < int64_t, 4 > cur = dims ; 9491do { 9492if ( cur != canonical ) { 9493test_cases . emplace_back ( new test_cpy( type , type , cur , canonical )); 9494} 9495if ( cur != reversed ) { 9496test_cases . emplace_back ( new test_cpy( type , type , cur , reversed )); 9497} 9498if ( cur [ 0 ] == 32 && type == GGML_TYPE_F32 ) { 9499if ( canonical [ 0 ] == 32 ) { 9500test_cases . emplace_back ( new test_cpy( GGML_TYPE_Q4_0 , GGML_TYPE_Q4_0 , cur , canonical )); 9501} 9502if ( reversed [ 0 ] == 32 ) { 9503test_cases . emplace_back ( new test_cpy( GGML_TYPE_Q4_0 , GGML_TYPE_Q4_0 , cur , reversed )); 9504} 9505} 9506std:: next_permutation ( cur . begin (), cur . end ()); 9507} while ( cur != canonical ); 9508} 9509} 9510 9511for (ggml_type type_dst : { GGML_TYPE_F32 , GGML_TYPE_I32 , GGML_TYPE_F16 , GGML_TYPE_BF16 }) { 9512for (bool use_view_slice : { true, false }) { 9513for (std::array < int64_t, 4 > ne : std::initializer_list < std::array < int64_t, 4 >> { { 2 , 1 , 1 , 1 }, { 2 , 1 , 3 , 5 }, 9514{ 2 , 3 , 5 , 7 }, { 1 , 4 , 4 , 1 }, { 1 , 8 , 17 , 1 }, { 10 , 10 , 10 , 1 } }) { 9515if ( use_view_slice && ( type_dst == GGML_TYPE_F16 || type_dst == GGML_TYPE_BF16 )) { 9516continue ; // TODO: add after WebGPU is fixed 9517} 9518test_cases . emplace_back ( new test_cont( type_dst , ne , use_view_slice )); 9519} 9520} 9521} 9522 9523for (ggml_type type_dst : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9524for (std::array < int64_t, 4 > ne : std::initializer_list < std::array < int64_t, 4 >> { 9525{ 10 , 10 , 10 , 1 }, { 33 , 5 , 7 , 1 }, { 64 , 3 , 65 , 1 }, { 2 , 3 , 5 , 7 }, 9526// large, tile-aligned and tile-unaligned, matching the perf cases 9527{ 1024 , 64 , 64 , 1 }, { 2304 , 64 , 64 , 1 }, { 1000 , 33 , 65 , 1 } }) { 9528for (std::array < int64_t, 4 > perm : std::initializer_list < std::array < int64_t, 4 >> { 9529{ 2 , 1 , 0 , 3 }, // 0<->2 swap 9530{ 1 , 2 , 0 , 3 }, // 3-cycle 9531{ 0 , 2 , 1 , 3 } }) { 9532test_cases . emplace_back ( new test_cont( type_dst , ne , false, perm )); 9533} 9534} 9535} 9536 9537auto add_test_bin_bcast = [ & ](ggml_type type , std::array < int64_t, 4 > ne , std::array < int, 4 > nr , bool perm1 = false, bool src_overlap = false) { 9538for (auto op : { ggml_add , ggml_sub , ggml_mul , ggml_div }) { 9539test_cases . emplace_back ( new test_bin_bcast( op , type , ne , nr , 1 , perm1 , src_overlap )); 9540} 9541}; 9542for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 9543for (bool perm1 : {false, true}) { 9544add_test_bin_bcast ( type , { 1 , 1 , 8 , 1 }, { 1 , 1 , 1 , 1 }, perm1 ); 9545add_test_bin_bcast ( type , { 1 , 1 , 1 , 1 }, { 32 , 1 , 1 , 1 }, perm1 ); 9546add_test_bin_bcast ( type , { 1 , 1 , 320 , 320 }, { 1 , 1 , 1 , 1 }, perm1 ); 9547add_test_bin_bcast ( type , { 10 , 5 , 1 , 1 }, { 1 , 1 , 1 , 1 }, perm1 ); 9548add_test_bin_bcast ( type , { 10 , 5 , 4 , 1 }, { 1 , 1 , 1 , 1 }, perm1 ); 9549add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, perm1 ); 9550add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 2 , 1 , 1 , 1 }, perm1 ); 9551add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 2 , 1 , 1 }, perm1 ); 9552add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 1 , 2 , 1 }, perm1 ); 9553add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 1 , 1 , 2 }, perm1 ); 9554add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 1 , 2 , 2 }, perm1 ); 9555add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 1 , 2 , 2 , 2 }, perm1 ); 9556add_test_bin_bcast ( type , { 10 , 5 , 4 , 3 }, { 2 , 2 , 2 , 2 }, perm1 ); 9557} 9558 9559// src_overlap 9560add_test_bin_bcast ( type , { 10 , 5 , 4 , 6 }, { 1 , 1 , 1 , 1 }, false, true); 9561add_test_bin_bcast ( type , { 10 , 5 , 4 , 5 }, { 1 , 1 , 1 , 1 }, false, true); 9562add_test_bin_bcast ( type , { 1 , 1 , 120 , 120 }, { 1 , 1 , 1 , 1 }, false, true); 9563add_test_bin_bcast ( type , { 1 , 1 , 4 , 320 }, { 1 , 1 , 1 , 1 }, false, true); 9564 9565// test case for k_bin_bcast_unravel in CUDA backend 9566add_test_bin_bcast ( type , { 1 , 1 , 65536 , 1 }, { 256 , 1 , 1 , 1 }); 9567 9568// stable diffusion 9569add_test_bin_bcast ( type , { 1280 , 1 , 1 , 1 }, { 1 , 1 , 1 , 1 }); 9570add_test_bin_bcast ( type , { 1280 , 1 , 1 , 1 }, { 1 , 16 , 16 , 1 }); 9571add_test_bin_bcast ( type , { 1280 , 16 , 16 , 1 }, { 1 , 1 , 1 , 1 }); 9572add_test_bin_bcast ( type , { 1280 , 1 , 1 , 1 }, { 1 , 256 , 1 , 1 }); 9573add_test_bin_bcast ( type , { 1 , 1 , 1280 , 1 }, { 16 , 16 , 1 , 1 }); 9574add_test_bin_bcast ( type , { 16 , 16 , 1280 , 1 }, { 1 , 1 , 1 , 1 }); 9575add_test_bin_bcast ( type , { 1 , 1 , 1920 , 1 }, { 16 , 16 , 1 , 1 }); 9576add_test_bin_bcast ( type , { 1 , 1 , 2560 , 1 }, { 16 , 16 , 1 , 1 }); 9577add_test_bin_bcast ( type , { 1 , 1 , 1280 , 1 }, { 32 , 32 , 1 , 1 }); 9578add_test_bin_bcast ( type , { 1 , 1 , 1920 , 1 }, { 32 , 32 , 1 , 1 }); 9579add_test_bin_bcast ( type , { 1 , 1 , 640 , 1 }, { 32 , 32 , 1 , 1 }); 9580add_test_bin_bcast ( type , { 5120 , 1 , 1 , 1 }, { 1 , 256 , 1 , 1 }); 9581add_test_bin_bcast ( type , { 640 , 1 , 1 , 1 }, { 1 , 1 , 1 , 1 }); 9582add_test_bin_bcast ( type , { 64 , 262144 , 1 , 1 }, { 1 , 1 , 1 , 1 }); 9583//add_test_bin_bcast(type, {3, 3, 2560, 1280}, {1, 1, 1, 1}); 9584//add_test_bin_bcast(type, {3, 3, 2560, 1280}, {2, 1, 1, 1}); 9585} 9586 9587// single inplace tests, especially important for WebGPU backend since kernels for inplace vs. not are different 9588test_cases . emplace_back ( new test_bin_bcast( ggml_add_inplace , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 16 )); 9589test_cases . emplace_back ( new test_bin_bcast( ggml_mul_inplace , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 16 )); 9590test_cases . emplace_back ( new test_bin_bcast( ggml_sub_inplace , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 16 )); 9591test_cases . emplace_back ( new test_bin_bcast( ggml_div_inplace , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 16 )); 9592 9593// fusion 9594test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 10 , 5 , 4 , 3 }, { 2 , 1 , 1 , 1 }, 2 )); 9595test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F16 , { 10 , 5 , 4 , 3 }, { 2 , 1 , 1 , 1 }, 2 )); 9596test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 2 , true)); 9597test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 2 , 1 , 1 }, 3 )); 9598test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 10 , 5 , 4 , 3 }, { 1 , 1 , 2 , 1 }, 4 )); 9599test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 2 }, 5 )); 9600test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 10 , 5 , 4 , 3 }, { 1 , 1 , 2 , 2 }, 6 )); 9601test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 10 , 5 , 4 , 3 }, { 1 , 2 , 2 , 2 }, 7 )); 9602test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 2 , 2 , 2 , 2 }, 8 )); 9603test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 16 , 5 , 4 , 3 }, { 1 , 1 , 1 , 1 }, 16 )); 9604 9605test_cases . emplace_back ( new test_scale()); 9606test_cases . emplace_back ( new test_scale( GGML_TYPE_F32 , { 10 , 10 , 10 , 10 }, 2.0f , 1.0f )); 9607test_cases . emplace_back ( new test_scale( GGML_TYPE_F32 , { 10 , 10 , 10 , 10 }, 2.0f , 1.0f , true)); // inplace test 9608test_cases . emplace_back ( new test_scale( GGML_TYPE_F32 , { 100 , 10 , 10 , 10 }, 2.0f , 1.0f )); 9609test_cases . emplace_back ( new test_softcap( GGML_TYPE_F32 , { 10 , 10 , 10 , 10 }, 50.0f )); 9610test_cases . emplace_back ( new test_silu_back()); 9611 9612for (float eps : { 0.0f , 1e-6f , 1e-4f , 1e-1f , 10.f }) { 9613for (uint32_t n : { 64 , 1025 }) { 9614for (bool v : { false, true }) { 9615test_cases . emplace_back ( new test_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, v , eps )); 9616test_cases . emplace_back ( new test_rms_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, v , eps )); 9617} 9618test_cases . emplace_back ( new test_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, false, eps , true)); 9619test_cases . emplace_back ( new test_rms_norm_back( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps )); 9620test_cases . emplace_back ( new test_l2_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , false)); 9621test_cases . emplace_back ( new test_l2_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , true)); 9622test_cases . emplace_back ( new test_l2_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , false, true)); 9623// sibling batching: strided (production shape) and contiguous, 2 and 4 wide 9624test_cases . emplace_back ( new test_l2_norm_batch( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, 2 , eps , true)); 9625test_cases . emplace_back ( new test_l2_norm_batch( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, 4 , eps , true)); 9626test_cases . emplace_back ( new test_l2_norm_batch( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, 4 , eps , false)); 9627} 9628// row lengths that are not a multiple of 32, for the scalar (33) and float4 (132, 260) paths 9629for (uint32_t n : { 33 , 132 , 260 }) { 9630for (bool v : { false, true }) { 9631test_cases . emplace_back ( new test_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, v , eps )); 9632test_cases . emplace_back ( new test_rms_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, v , eps )); 9633} 9634} 9635} 9636 9637// in-place tests 9638test_cases . emplace_back ( new test_rms_norm( GGML_TYPE_F32 , { 64 , 5 , 4 , 3 }, false, 1e-6f , true)); 9639 9640for (ggml_type set_rows_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9641test_cases . emplace_back ( new test_rms_norm_mul_rope({ 256 , 1 , 1 , 1 }, 1e-6f , false, true, false, GGML_ROPE_TYPE_NORMAL , false, false, set_rows_type )); 9642test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 4 , 3 , 1 }, 1e-6f , false, true, false, GGML_ROPE_TYPE_NORMAL , false, false, set_rows_type )); 9643} 9644 9645for (float eps : { 0.0f , 1e-6f , 1e-4f , 1e-1f , 1.0f }) { 9646for (uint32_t n : { 64 , 1025 }) { 9647test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , false)); 9648test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , true)); 9649test_cases . emplace_back ( new test_norm_mul_add( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , false)); 9650test_cases . emplace_back ( new test_norm_mul_add( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , true)); 9651test_cases . emplace_back ( new test_add_rms_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , false)); 9652test_cases . emplace_back ( new test_add_rms_norm( GGML_TYPE_F32 , { n , 5 , 4 , 3 }, eps , true)); 9653} 9654} 9655for (uint32_t n : { 1 , 511 , 1025 , 8192 , 33 * 512 }) { 9656for (bool multi_add : {false, true}) { 9657test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { n , 1 , 1 , 1 }, 1e-6f , false, multi_add )); 9658} 9659test_cases . emplace_back ( new test_add_rms_norm( GGML_TYPE_F32 , { n , 1 , 1 , 1 }, 1e-6f , false)); 9660} 9661for (uint32_t n : { 64 , 1025 }) { 9662test_cases . emplace_back ( new test_add_add( GGML_TYPE_F32 , GGML_TYPE_F32 , { n , 5 , 4 , 3 }, false, false)); 9663test_cases . emplace_back ( new test_add_add( GGML_TYPE_F32 , GGML_TYPE_F32 , { n , 5 , 4 , 3 }, true, false)); 9664test_cases . emplace_back ( new test_add_add( GGML_TYPE_F32 , GGML_TYPE_F32 , { n , 5 , 4 , 3 }, false, true)); 9665test_cases . emplace_back ( new test_add_add( GGML_TYPE_F16 , GGML_TYPE_F16 , { n , 5 , 4 , 3 }, false, false)); 9666test_cases . emplace_back ( new test_add_add( GGML_TYPE_F16 , GGML_TYPE_F32 , { n , 5 , 4 , 3 }, false, false)); 9667test_cases . emplace_back ( new test_add_add( GGML_TYPE_F16 , GGML_TYPE_F32 , { n , 5 , 4 , 3 }, true, false)); 9668} 9669 9670test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 1536 , 1 , 1 , 1 }, 1e-6f , false, false, true)); 9671test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 256 , 4 , 1 , 1 }, 1e-6f , false, false, true)); 9672test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 256 , 4 , 3 , 2 }, 1e-6f , false, false, true)); 9673test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 256 , 4 , 3 , 2 }, 1e-6f , false, false, true, false, true)); 9674test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 1536 , 1 , 1 , 1 }, 1e-6f , false, false, false, true)); 9675test_cases . emplace_back ( new test_rms_norm_mul_add( GGML_TYPE_F32 , { 256 , 4 , 1 , 1 }, 1e-6f , false, false, false, true)); 9676 9677test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 4 , 7 , 2 })); 9678test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 4 , 7 , 2 }, 1e-6f , false, true)); 9679 9680for (auto multi_add : {false, true}) { 9681for (auto set_rows : {false, true}) { 9682for (auto broadcast : {false, true}) { 9683for (auto rope : { GGML_ROPE_TYPE_NORMAL , GGML_ROPE_TYPE_NEOX , GGML_ROPE_TYPE_IMROPE }) { 9684test_cases . emplace_back ( new test_rms_norm_mul_rope({ 768 , 1 , 1 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9685test_cases . emplace_back ( new test_rms_norm_mul_rope({ 768 , 3 , 1 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9686test_cases . emplace_back ( new test_rms_norm_mul_rope({ 768 , 3 , 5 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9687test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 32 , 2 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9688test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 4 , 2 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9689test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 32 , 50 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9690test_cases . emplace_back ( new test_rms_norm_mul_rope({ 128 , 4 , 50 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9691test_cases . emplace_back ( new test_rms_norm_mul_rope({ 8192 , 2 , 2 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9692test_cases . emplace_back ( new test_rms_norm_mul_rope({ 8192 , 2 , 2 , 1 }, 1e-6f , multi_add , set_rows , broadcast , rope )); 9693} 9694} 9695} 9696} 9697for (int64_t d_conv : { 3 , 4 , 9 }) { 9698for (int64_t d_inner : { 1024 , 1536 , 2048 }) { 9699test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { d_conv , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 })); 9700test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { 2 * d_conv , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 })); 9701test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { d_conv , d_inner , 4 , 1 }, { d_conv , d_inner , 1 , 1 })); 9702// long token (n_t > 32, exercises the long_token kernel path) 9703test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { d_conv - 1 + 64 , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 })); 9704test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { d_conv - 1 + 64 , d_inner , 4 , 1 }, { d_conv , d_inner , 1 , 1 })); 9705} 9706} 9707 9708// fused ssm_conv + (optional) bias_add + silu. The bias-only graph (no silu) is intentionally 9709// not tested since there's no fusion for that pattern in ggml_cuda_can_fuse. 9710for (int64_t d_conv : { 3 , 4 , 9 }) { 9711for (int64_t d_inner : { 1024 , 1536 , 2048 }) { 9712for (bool fuse_bias : {false, true}) { 9713// short token path (n_t <= 32) 9714test_cases . emplace_back ( new test_ssm_conv_bias_silu( 9715GGML_TYPE_F32 , { d_conv , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 }, fuse_bias )); 9716test_cases . emplace_back ( new test_ssm_conv_bias_silu( 9717GGML_TYPE_F32 , { 2 * d_conv , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 }, fuse_bias )); 9718test_cases . emplace_back ( new test_ssm_conv_bias_silu( 9719GGML_TYPE_F32 , { d_conv , d_inner , 4 , 1 }, { d_conv , d_inner , 1 , 1 }, fuse_bias )); 9720// long token path (n_t > 32) 9721test_cases . emplace_back ( new test_ssm_conv_bias_silu( 9722GGML_TYPE_F32 , { d_conv - 1 + 64 , d_inner , 1 , 1 }, { d_conv , d_inner , 1 , 1 }, fuse_bias )); 9723test_cases . emplace_back ( new test_ssm_conv_bias_silu( 9724GGML_TYPE_F32 , { d_conv - 1 + 64 , d_inner , 4 , 1 }, { d_conv , d_inner , 1 , 1 }, fuse_bias )); 9725} 9726} 9727} 9728 9729test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 16 , 1 , 1024 , 1 , 32 , 4 )); // Mamba-1 9730test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 32 , 4 )); // Mamba-2 9731test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 256 , 64 , 8 , 2 , 32 , 4 )); // Falcon-H1 9732test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 128 , 4 , 4 , 16 , 2 , true)); // x/B/C overlap 9733test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 80 , 128 , 1 , 256 , 1 )); // Nemotron-9B SSD path 9734test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 80 , 128 , 1 , 512 , 1 )); // Nemotron-9B SSD multi-chunk (2 aligned chunks) 9735test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 80 , 8 , 300 , 2 )); // Mamba-2 SSD multi-chunk (partial 2nd chunk, 2 seqs) 9736test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 4 , 2 , false, /*K=*/ 4 )); // Mamba-2 rollback snapshots 9737test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 8 , 2 , false, /*K=*/ 3 )); // Mamba-2 rollback overflow 9738test_cases . emplace_back ( new test_ssm_scan_rollback( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 8 , 2 , /*K=*/ 3 )); // rollback snapshots match prefix states 9739test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 64 , 4 )); // Metal SSD one chunk MMA only, no seq tail 9740test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 65 , 2 )); // SSD one chunk + 1-token sequential tail 9741test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 128 , 2 )); // SSD multi-chunk, no tail (exercises the chunk-to-chunk state handoff) 9742test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 16 , 2 , 128 , 2 , false, /*K=*/ 1 , /*weak_decay=*/ true)); // SSD multi-chunk, carried state not numerically negligible 9743 9744test_cases . emplace_back ( new test_rwkv_wkv6( GGML_TYPE_F32 , 32 , 64 , 1 , 1 )); 9745test_cases . emplace_back ( new test_rwkv_wkv6( GGML_TYPE_F32 , 32 , 64 , 32 , 1 )); 9746test_cases . emplace_back ( new test_rwkv_wkv6( GGML_TYPE_F32 , 32 , 64 , 32 , 4 )); 9747test_cases . emplace_back ( new test_rwkv_wkv6( GGML_TYPE_F32 , 32 , 64 , 128 , 4 )); 9748 9749test_cases . emplace_back ( new test_rwkv_wkv7( GGML_TYPE_F32 , 32 , 64 , 1 , 1 )); 9750test_cases . emplace_back ( new test_rwkv_wkv7( GGML_TYPE_F32 , 32 , 64 , 1 , 4 )); 9751test_cases . emplace_back ( new test_rwkv_wkv7( GGML_TYPE_F32 , 32 , 64 , 32 , 1 )); 9752test_cases . emplace_back ( new test_rwkv_wkv7( GGML_TYPE_F32 , 32 , 64 , 32 , 4 )); 9753test_cases . emplace_back ( new test_rwkv_wkv7( GGML_TYPE_F32 , 32 , 64 , 128 , 4 )); 9754 9755test_cases . emplace_back ( new test_gla( GGML_TYPE_F32 , 32 , 64 , 1 , 1 )); 9756test_cases . emplace_back ( new test_gla( GGML_TYPE_F32 , 32 , 64 , 32 , 1 )); 9757test_cases . emplace_back ( new test_gla( GGML_TYPE_F32 , 32 , 64 , 32 , 4 )); 9758test_cases . emplace_back ( new test_gla( GGML_TYPE_F32 , 32 , 64 , 128 , 4 )); 9759 9760// FWHT tests 9761test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 1 , 128 )); 9762test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 1 , 64 )); 9763test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 256 , 1 , 256 )); 9764test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 512 , 1 , 512 )); 9765test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 32 , 128 )); 9766test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 4 , 128 , { 2 , 3 })); 9767test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 256 , 512 , 256 )); // many rows 9768test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 32 , 1 , 32 )); // too small (N<64) 9769test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 1024 , 1 , 1024 )); // too big (N>512) 9770 9771#if 0 9772// > 4GB A matrix. Too slow to be enabled by default. 9773test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 900000 , 3 , 2592 , { 1 , 1 }, { 1 , 1 })); 9774test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 1700000 , 96 , 2592 , { 1 , 1 }, { 1 , 1 })); 9775test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 1700000 , 3 , 2592 , { 1 , 1 }, { 1 , 1 })); 9776test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 1700000 , 1 , 2592 , { 1 , 1 }, { 1 , 1 })); 9777 9778test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 128 , 128 , false, 8192 , 2 , 5120 )); // Llama-4-Maverick-17B-128E-PAB-Q8_0 9779test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 128 , 128 , false, 8192 , 1 , 5120 )); // Llama-4-Maverick-17B-128E-PAB-Q8_0 9780test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 8192 , 1 , 5120 , { 128 , 1 }, { 1 , 1 })); 9781test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 8192 , 512 , 5120 , { 128 , 1 }, { 1 , 1 })); 9782#endif 9783 9784for (ggml_type type_a : all_types ) { 9785for (int i = 1 ; i < 10 ; ++ i ) { 9786test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 16 , i , 1 * 256 , { 1 , 1 }, { 1 , 1 })); 9787//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 12, i, 2*256, { 2, 1}, {1, 1})); 9788//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 11, i, 3*256, { 1, 3}, {5, 1})); 9789//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 13, i, 4*256, { 2, 3}, {1, 1})); 9790//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 17, i, 31*256, { 4, 1}, {1, 1})); 9791//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 18, i, 32*256, { 1, 1}, {8, 1})); 9792//test_cases.emplace_back(new test_mul_mat(type_a, GGML_TYPE_F32, 19, i, 33*256, { 1, 1}, {1, 1})); 9793} 9794// mat-vec shaders split k across lanes and loop over the blocks in strides. k must be 9795// long enough that the loop wraps, else the stride is never exercised 9796test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 16 , 1 , 16 * 256 , { 1 , 1 }, { 1 , 1 })); 9797test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 16 , 8 , 16 * 256 , { 1 , 1 }, { 1 , 1 })); 9798} 9799 9800// Multi-column MMVQ coverage for the Q4_K weight-reuse path and a Q5_K control. 9801for (ggml_type type_a : { GGML_TYPE_Q4_K , GGML_TYPE_Q5_K }) { 9802for (int n = 1 ; n <= 8 ; ++ n ) { 9803test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 4096 , n , 1024 , { 1 , 1 }, { 1 , 1 })); 9804test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 1023 , n , 4096 , { 1 , 1 }, { 1 , 1 })); 9805} 9806} 9807 9808// The SYCL backend picks between one and two output rows per subgroup by row count when there 9809// are two destination columns (Q4_K_MMVQ_ROW_PAIR_MIN_NROWS in ggml-sycl/mmvq.cpp). Cover both 9810// sides of that boundary, including an odd row count above it for the row-pair tail. 9811for (int64_t m : { 6271 , 6272 , 6273 }) { 9812test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q4_K , GGML_TYPE_F32 , m , 2 , 1024 , { 1 , 1 }, { 1 , 1 })); 9813} 9814 9815test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , 2880 , 32 , 2880 , { 1 , 1 }, { 1 , 1 })); 9816test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 2880 , 32 , 2880 , { 1 , 1 }, { 1 , 1 })); 9817test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_MXFP4 , GGML_TYPE_F32 , 2880 , 32 , 2880 , { 1 , 1 }, { 1 , 1 })); 9818 9819// m == 1, with n on both sides of MMVF_MAX_BATCH_SIZE (8): mmvf below, operand swap above 9820for (int64_t n : { 1 , 7 , 8 , 9 , 16 , 127 , 128 , 511 , 512 }) { 9821test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 1 , n , 2048 , { 1 , 1 }, { 1 , 1 })); 9822} 9823test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 1 , 512 , 2048 , { 1 , 1 }, { 1 , 1 })); 9824test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 1 , 512 , 2048 , { 1 , 1 }, { 1 , 1 })); 9825test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 1 , 509 , 2051 , { 1 , 1 }, { 1 , 1 })); 9826test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 1 , 509 , 2051 , { 1 , 1 }, { 1 , 1 })); 9827 9828test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 31 , 509 , 2051 , { 1 , 1 }, { 1 , 1 })); 9829test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 32 , 509 , 2112 , { 1 , 1 }, { 1 , 1 })); 9830test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 32 , 509 , 2112 , { 1 , 1 }, { 1 , 1 })); 9831 9832#if 0 9833{ 9834// Test paths in OpenCL 9835std::vector < int > ns = { 32 , 64 , 128 , 256 , 512 , 1024 , 4096 }; 9836std::vector < int > ks = { 896 , 1536 , 4096 }; 9837for (auto n : ns ) { 9838for (auto k : ks ) { 9839test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 1024 , n , k , { 1 , 1 }, { 1 , 1 })); 9840} 9841} 9842} 9843#endif 9844 9845#if 1 9846for (ggml_type type_a : base_types ) { 9847for (ggml_type type_b : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 9848std::vector < int > ks = { 256 }; 9849if ( ggml_blck_size ( type_a ) == 1 ) { 9850ks . push_back ( 4 ); 9851} 9852for (auto k : ks ) { 9853// test cases without permutation 9854test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 1 , 1 }, { 1 , 1 })); 9855test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 1 , 1 }, { 2 , 1 })); 9856test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 1 , 1 }, { 1 , 2 })); 9857test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 1 }, { 1 , 1 })); 9858test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 1 }, { 2 , 1 })); 9859test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 2 }, { 1 , 1 })); 9860test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 2 }, { 2 , 1 })); 9861test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 2 }, { 1 , 2 })); 9862test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 3 , 2 }, { 2 , 2 })); 9863test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 4 , k , { 3 , 2 }, { 2 , 2 })); 9864 9865test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 1 , 1 }, { 1 , 1 })); 9866test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 1 , 1 }, { 2 , 1 })); 9867test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 1 , 1 }, { 1 , 2 })); 9868test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 1 }, { 1 , 1 })); 9869test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 1 }, { 2 , 1 })); 9870test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 2 }, { 1 , 1 })); 9871test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 2 }, { 2 , 1 })); 9872test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 2 }, { 1 , 2 })); 9873test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 3 , 2 }, { 2 , 2 })); 9874 9875// test cases with permutation 9876test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9877test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9878test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9879 9880test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 4 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9881test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 8 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9882test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 8 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9883test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 8 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9884 9885test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9886test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9887test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , k , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9888} 9889 9890// test cases with large ne00/ne10 to cover stream-k fixup 9891test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , 1024 , { 3 , 2 }, { 1 , 1 })); 9892test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 8 , 1024 , { 3 , 2 }, { 1 , 1 })); 9893test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 16 , 1024 , { 3 , 2 }, { 1 , 1 })); 9894 9895// test cases with large batch size 9896test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 8 , 256 , { 1536 , 1 }, { 1 , 1 })); 9897} 9898} 9899 9900// BF16 is absent from base_types: add the 3 standard non-contig permutations explicitly 9901test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 1 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9902test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 1 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9903test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 1 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9904test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 8 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9905test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 8 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9906test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 8 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9907test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 2 , 1 , 3 })); 9908test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 1 , 3 , 2 })); 9909test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , 256 , { 2 , 3 }, { 1 , 1 }, { 0 , 3 , 2 , 1 })); 9910 9911// token-tile boundary coverage. With n_used == n_mats every token routes to every expert, so 9912// each expert receives exactly n rows, with no dependence on the random draw. mul_mm_id is used 9913// from 32 tokens up: n = 32, 33, 47, 48, 49 reach it, leaving a last tile of 32, 1, 15, 16 and 9914// 17 rows - 16 and 17 straddle the point where the upper half stops being skipped. The smaller 9915// n cover the same row counts on the mat-vec path. 9916for (ggml_type type_a : { GGML_TYPE_Q4_K , GGML_TYPE_IQ2_XS , GGML_TYPE_F16 }) { 9917for (int n : { 1 , 15 , 16 , 17 , 31 , 32 , 33 , 47 , 48 , 49 }) { 9918test_cases . emplace_back ( new test_mul_mat_id( type_a , GGML_TYPE_F32 , 4 , 4 , false, 512 , n , 256 )); 9919} 9920// experts that receive no rows at all 9921test_cases . emplace_back ( new test_mul_mat_id( type_a , GGML_TYPE_F32 , 8 , 1 , false, 512 , 1 , 256 )); 9922} 9923 9924for (ggml_type type_a : other_types ) { 9925for (ggml_type type_b : { GGML_TYPE_F32 }) { 9926if ( ggml_blck_size ( type_a ) != 256 ) { 9927test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , ggml_blck_size ( type_a ), { 1 , 1 }, { 1 , 1 })); 9928} 9929test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 16 , 1 , 256 , { 1 , 1 }, { 1 , 1 })); 9930} 9931} 9932 9933// Test IQP panel path for all grid IQ types 9934for (ggml_type type_a : { GGML_TYPE_IQ2_XXS , GGML_TYPE_IQ2_XS , GGML_TYPE_IQ2_S , GGML_TYPE_IQ3_XXS , 9935GGML_TYPE_IQ3_S , GGML_TYPE_IQ1_S , GGML_TYPE_IQ1_M , GGML_TYPE_IQ4_XS }) { 9936test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 16 , 10 , 256 , { 1 , 1 }, { 1 , 1 })); 9937} 9938#else 9939// m = a rows 9940// n = b rows 9941// k = cols 9942std::uniform_int_distribution <> dist_m ( 1 , 128 ); 9943std::uniform_int_distribution <> dist_n ( 16 , 128 ); 9944std::uniform_int_distribution <> dist_k ( 1 , 16 ); 9945for (int i = 0 ; i < 1000 ; i ++ ) { 9946for (ggml_type type_a : all_types ) { 9947for (ggml_type type_b : { GGML_TYPE_F32 }) { 9948int m = dist_m ( rng ); 9949int n = dist_n ( rng ); 9950int k = dist_k ( rng ) * ggml_blck_size ( type_a ); 9951test_cases . emplace_back ( new test_mul_mat( type_a , type_b , m , n , k , { 1 , 1 }, { 1 , 1 })); 9952} 9953} 9954} 9955#endif 9956 9957test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 2 , 128 , { 8 , 1 }, { 1 , 1 })); 9958test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 83 , 2 , 128 , { 8 , 1 }, { 4 , 1 })); 9959test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 2 , 64 , { 8 , 1 }, { 4 , 1 })); 9960test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 83 , 2 , 64 , { 8 , 1 }, { 4 , 1 })); 9961test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 45 , 128 , { 8 , 1 }, { 4 , 1 })); 9962test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 128 , 45 , 64 , { 8 , 1 }, { 4 , 1 })); 9963test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 1056 , 1 , 193 , { 1 , 1 }, { 4 , 1 }, { 0 , 2 , 1 , 3 })); 9964test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 1056 , 1 , 67 , { 1 , 1 }, { 4 , 1 }, { 0 , 2 , 1 , 3 })); 9965test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 16 , 32 , 32 , { 1 , 1 }, { 1 , 1 }, { 0 , 1 , 2 , 3 }, 64 , 3 )); 9966test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 77 , 77 , { 12 , 1 }, { 1 , 1 })); 9967test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 32 , 4 , 96 , { 3 , 2 }, { 1 , 1 }, { 0 , 1 , 2 , 3 }, 0 , 1 , true)); 9968 9969test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , 576 , 512 , 576 , { 1 , 1 }, { 1 , 1 })); 9970test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , 1 , 2048 , 8192 , { 1 , 1 }, { 1 , 1 })); 9971for (ggml_type type_a : all_types ) { 9972test_cases . emplace_back ( new test_mul_mat( type_a , GGML_TYPE_F32 , 1 , 64 , 256 , { 1 , 1 }, { 1 , 1 })); 9973} 9974 9975test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q8_0 , GGML_TYPE_F32 , 6 , 4096 , 5120 , { 1 , 1 }, { 1 , 1 })); 9976 9977// K not a multiple of 32 9978test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 64 , 32 , 65 , { 1 , 1 }, { 1 , 1 })); 9979test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 64 , 32 , 80 , { 1 , 1 }, { 1 , 1 })); 9980test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 32 , 80 , { 1 , 1 }, { 1 , 1 })); 9981test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 32 , 80 , { 1 , 1 }, { 1 , 1 })); 9982test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 64 , 32 , 588 , { 1 , 1 }, { 1 , 1 })); // 14*14*3, e.g. conv_2d im2col 9983test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F16 , 64 , 32 , 80 , { 4 , 1 }, { 1 , 1 })); 9984 9985#if 0 9986// test the mat-mat path for Metal 9987for (int k = 1 ; k < 512 ; ++ k ) { 9988test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 127 , k , { 12 , 1 }, { 1 , 1 })); 9989test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 127 , k , { 12 , 1 }, { 1 , 1 })); 9990test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 77 , k , { 12 , 1 }, { 1 , 1 })); 9991test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 77 , k , { 12 , 1 }, { 1 , 1 })); 9992test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 64 , 128 , k , { 12 , 1 }, { 1 , 1 })); 9993test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 128 , k , { 12 , 1 }, { 1 , 1 })); 9994test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 16 , 16 , false, 50 , 200 , k )); 9995test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 16 , 16 , true, 50 , 200 , k )); 9996test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , false, 50 , 200 , k )); 9997test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , true, 50 , 200 , k )); 9998test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F32 , GGML_TYPE_F32 , 16 , 16 , false, 50 , 200 , k )); 9999test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F32 , GGML_TYPE_F32 , 16 , 16 , true, 50 , 200 , k )); 10000} 10001#endif 10002 10003for (auto bs2 : { 1 , 3 }) { 10004for (auto bs : { 1 , 2 , 4 , 8 }) { 10005for (auto nr : { 1 , 4 }) { 10006for (uint32_t m = 0 ; m < 2 ; ++ m ) { 10007for (uint32_t k = 0 ; k < 2 ; ++ k ) { 10008for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_F32 }) { 10009test_cases . emplace_back ( new test_mul_mat( type , GGML_TYPE_F32 , 1056 + m , 1 , 128 + k , { bs , bs2 }, { nr , 1 }, { 0 , 2 , 1 , 3 })); 10010test_cases . emplace_back ( new test_mul_mat( type , GGML_TYPE_F32 , 128 + m , 1 , 1056 + k , { bs , bs2 }, { nr , 1 }, { 0 , 1 , 2 , 3 }, 2 * 1056 + k )); 10011} 10012} 10013} 10014} 10015} 10016} 10017 10018// sycl backend will limit task global_range < MAX_INT 10019// test case for f16-type-convert-to-fp32 kernel with large k under fp32 compute dtype (occurs in stable-diffusion) 10020// however this case needs to alloc more memory which may fail in some devices (Intel Arc770, etc.) 10021// this case is verified (pass) in Intel(R) Data Center GPU Max 1100 (sycl backend) and NV A30 (cuda backend) 10022// test_cases.emplace_back(new test_mul_mat(GGML_TYPE_F16, GGML_TYPE_F16, 512, 262144, 9216, {1, 1}, {1, 1})); 10023 10024// test large experts*tokens 10025for (bool b : {false, true}) { 10026test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 16 , 16 , b , 32 , 1024 , 16 )); 10027test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 2 , 2 , b , 32 , 8192 , 64 )); 10028test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 16 , 16 , b , 50 , 200 , 64 )); 10029test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , b , 32 , 1024 , 16 )); 10030test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_BF16 , GGML_TYPE_F32 , 16 , 16 , b , 50 , 200 , 64 )); 10031} 10032 10033// For issue 27873 10034test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_IQ2_XXS , GGML_TYPE_F32 , 1 , 1 , false, 1 , 8192 , 4096 )); 10035 10036for (int k : { 1 , 63 , 65 }) { 10037test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_F16 , GGML_TYPE_F32 , 1 , 1 , false, 8 , 16 , k )); 10038} 10039test_cases . emplace_back ( new test_mul_mat_id_fusion( GGML_TYPE_F16 , GGML_TYPE_F32 , 16 , 16 , false, 32 , 32 , 32 , 3 )); 10040 10041// gpt-oss issue with Vulkan mmq_id 10042test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_MXFP4 , GGML_TYPE_F32 , 32 , 2 , false, 2880 , 32 , 2880 )); 10043test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , 32 , 2 , false, 2880 , 32 , 2880 )); 10044 10045// multiple blocks per row: exercises the block-stride loop and the 10046// per-expert base offset, which k == 256 alone leaves untested 10047test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_TQ1_0 , GGML_TYPE_F32 , 28 , 10 , false, 1024 , 1 , 4096 )); 10048test_cases . emplace_back ( new test_mul_mat_id( GGML_TYPE_TQ1_0 , GGML_TYPE_F32 , 128 , 8 , false, 1024 , 1 , 2048 )); 10049 10050for (ggml_type type_a : all_types ) { 10051test_cases . emplace_back ( new test_mul_mat_id( type_a , GGML_TYPE_F32 , 4 , 2 , false, 64 , 16 , 3 * ggml_blck_size ( type_a ))); 10052} 10053 10054// Test IQP panel path for all grid IQ types 10055for (ggml_type type_a : { GGML_TYPE_IQ2_XXS , GGML_TYPE_IQ2_XS , GGML_TYPE_IQ2_S , GGML_TYPE_IQ3_XXS , 10056GGML_TYPE_IQ3_S , GGML_TYPE_IQ1_S , GGML_TYPE_IQ1_M , GGML_TYPE_IQ4_XS }) { 10057test_cases . emplace_back ( new test_mul_mat_id( type_a , GGML_TYPE_F32 , 4 , 4 , false, 16 , 10 , 256 )); 10058} 10059 10060for (ggml_type type_a : base_types ) { 10061for (ggml_type type_b : { GGML_TYPE_F32 /*, GGML_TYPE_F16 */ }) { 10062for (int n_mats : { 4 , 8 }) { 10063for (int n_used : { 1 , 2 , 4 }) { 10064for (bool b : {false, true}) { 10065for (int n : { 1 , 4 , 5 , 17 , 32 , 129 }) { 10066int m = 512 ; 10067int k = 256 ; 10068test_cases . emplace_back ( new test_mul_mat_id( type_a , type_b , n_mats , n_used , b , m , n , k )); 10069} 10070} 10071} 10072} 10073} 10074} 10075 10076for (ggml_type type_a : other_types ) { 10077for (ggml_type type_b : { GGML_TYPE_F32 /*, GGML_TYPE_F16 */ }) { 10078for (int n_mats : { 4 }) { 10079for (int n_used : { 2 }) { 10080for (bool b : {false}) { 10081for (int n : { 1 , 32 }) { 10082int m = 512 ; 10083int k = 256 ; 10084test_cases . emplace_back ( new test_mul_mat_id( type_a , type_b , n_mats , n_used , b , m , n , k )); 10085} 10086} 10087} 10088} 10089} 10090} 10091 10092for (int bs : { 1 , 4 , 512 }) { 10093for (ggml_type type_a : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_Q4_0 , GGML_TYPE_Q4_K }) { 10094for (ggml_type type_b : { GGML_TYPE_F32 }) { 10095// test with mul after (ffn_moe_weighted) 10096test_cases . emplace_back ( new test_mul_mat_id_fusion( type_a , type_b , 128 , 8 , false, 768 , bs , 2048 , 1 , true)); 10097} 10098} 10099} 10100 10101for (ggml_type type_a : base_types ) { 10102for (ggml_type type_b : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10103for (int n : { 1 , 16 }) { 10104for (int k : { 1 , 16 }) { 10105for (int bs2 : { 1 , 3 }) { 10106for (int bs3 : { 1 , 3 }) { 10107for (int nr2 : { 1 , 2 }) { 10108for (int nr3 : { 1 , 2 }) { 10109test_cases . emplace_back ( new test_out_prod( type_a , type_b , 256 , n , k , { bs2 , bs3 }, { nr2 , nr3 })); 10110} 10111} 10112} 10113} 10114} 10115} 10116} 10117} 10118 10119// ne2 sweep to cover the cublasSgemmStridedBatched path (dps2 == 1, ne2 > 1) 10120for (int64_t ne2 : { 1 , 8 , 16 , 32 }) { 10121test_cases . emplace_back ( new test_out_prod( GGML_TYPE_F32 , GGML_TYPE_F32 , 10122256 , 16 , 16 , { ne2 , 1 }, { 1 , 1 })); 10123} 10124 10125// nr2 sweep to cover the cublasSgemmBatched pointer-array path (dps2 > 1) 10126for (int64_t nr2 : { 8 , 16 , 32 }) { 10127test_cases . emplace_back ( new test_out_prod( GGML_TYPE_F32 , GGML_TYPE_F32 , 10128256 , 16 , 16 , { 1 , 1 }, { nr2 , 1 })); 10129} 10130 10131// add_id 10132for (ggml_type type_a : { GGML_TYPE_F32 }) { 10133for (ggml_type type_b : { GGML_TYPE_F32 }) { 10134for (int n_mats : { 4 , 8 }) { 10135for (int n_used : { 1 , 2 , 4 }) { 10136for (int n_embd : { 32 , 129 }) { 10137for (int n_token : { 1 , 32 , 129 }) { 10138test_cases . emplace_back ( new test_add_id( type_a , type_b , n_embd , n_mats , n_used , n_token )); 10139} 10140} 10141} 10142} 10143} 10144} 10145 10146for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 10147test_cases . emplace_back ( new test_sqr ( type )); 10148test_cases . emplace_back ( new test_sqrt ( type )); 10149test_cases . emplace_back ( new test_log ( type )); 10150test_cases . emplace_back ( new test_sin ( type )); 10151test_cases . emplace_back ( new test_cos ( type )); 10152test_cases . emplace_back ( new test_clamp ( type )); 10153test_cases . emplace_back ( new test_leaky_relu( type )); 10154test_cases . emplace_back ( new test_floor ( type )); 10155test_cases . emplace_back ( new test_ceil ( type )); 10156test_cases . emplace_back ( new test_round ( type )); 10157test_cases . emplace_back ( new test_trunc ( type )); 10158test_cases . emplace_back ( new test_sqr ( type , { 7 , 1 , 5 , 3 })); 10159test_cases . emplace_back ( new test_sqr ( type , { 1024 , 1024 , 1 , 1 })); 10160test_cases . emplace_back ( new test_sqrt ( type , { 7 , 1 , 5 , 3 })); 10161test_cases . emplace_back ( new test_sqrt ( type , { 1024 , 1024 , 1 , 1 })); 10162test_cases . emplace_back ( new test_log ( type , { 7 , 1 , 5 , 3 })); 10163test_cases . emplace_back ( new test_log ( type , { 1024 , 1024 , 1 , 1 })); 10164test_cases . emplace_back ( new test_sin ( type , { 7 , 1 , 5 , 3 })); 10165test_cases . emplace_back ( new test_sin ( type , { 1024 , 1024 , 1 , 1 })); 10166test_cases . emplace_back ( new test_cos ( type , { 7 , 1 , 5 , 3 })); 10167test_cases . emplace_back ( new test_cos ( type , { 1024 , 1024 , 1 , 1 })); 10168test_cases . emplace_back ( new test_clamp ( type , { 7 , 1 , 5 , 3 })); 10169test_cases . emplace_back ( new test_clamp ( type , { 1024 , 1024 , 1 , 1 })); 10170test_cases . emplace_back ( new test_leaky_relu( type , { 7 , 1 , 5 , 3 })); 10171test_cases . emplace_back ( new test_leaky_relu( type , { 1024 , 1024 , 1 , 1 })); 10172test_cases . emplace_back ( new test_floor ( type , { 7 , 1 , 5 , 3 })); 10173test_cases . emplace_back ( new test_floor ( type , { 1024 , 1024 , 1 , 1 })); 10174test_cases . emplace_back ( new test_ceil ( type , { 7 , 1 , 5 , 3 })); 10175test_cases . emplace_back ( new test_ceil ( type , { 1024 , 1024 , 1 , 1 })); 10176test_cases . emplace_back ( new test_round ( type , { 7 , 1 , 5 , 3 })); 10177test_cases . emplace_back ( new test_round ( type , { 1024 , 1024 , 1 , 1 })); 10178test_cases . emplace_back ( new test_trunc ( type , { 7 , 1 , 5 , 3 })); 10179test_cases . emplace_back ( new test_trunc ( type , { 1024 , 1024 , 1 , 1 })); 10180} 10181 10182test_cases . emplace_back ( new test_diag_mask_inf( GGML_TYPE_F32 , { 10 , 10 , 1 , 1 }, 5 )); 10183test_cases . emplace_back ( new test_diag_mask_inf( GGML_TYPE_F32 , { 10 , 10 , 3 , 1 }, 5 )); 10184test_cases . emplace_back ( new test_diag_mask_inf( GGML_TYPE_F32 , { 10 , 10 , 3 , 2 }, 5 )); 10185 10186#if 0 10187std::uniform_int_distribution <> dist_ne1 ( 1 , 50 ); 10188int exponent = 1 ; 10189while ( exponent < ( 1 << 17 )) { 10190std::uniform_int_distribution <> dist_ne0 ( exponent , 2 * exponent ); 10191 10192for (int n = 0 ; n < 10 ; ++ n ) { 10193int64_t ne0 = dist_ne0 ( rng ); 10194int64_t ne1 = dist_ne1 ( rng ); 10195test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , GGML_TYPE_F32 , { ne0 , ne1 , 1 , 1 }, n / 2 == 0 , 0.1f , ne0 < 1000 ? 4.0f : 0.0f )); 10196} 10197 10198exponent <<= 1 ; 10199} 10200#endif 10201for (bool mask : {false, true}) { 10202for (bool sinks : {false, true}) { 10203for (float max_bias : { 0.0f , 8.0f }) { 10204if (! mask && max_bias > 0.0f ) continue ; 10205for (float scale : { 1.0f , 0.1f }) { 10206for (int64_t ne0 : { 16 , 1024 }) { 10207for (int64_t ne1 : { 16 , 1024 }) { 10208if ( mask ) { 10209for (ggml_type m_prec : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10210test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 , ne1 , 1 , 1 }, mask , sinks , m_prec , { 1 , 1 }, scale , max_bias )); 10211test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 - 1 , ne1 - 1 , 1 , 1 }, mask , sinks , m_prec , { 1 , 1 }, scale , max_bias )); 10212 10213if ( ne0 <= 32 && ne1 <= 32 ) { 10214test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 , ne1 , 1 , 3 }, mask , sinks , m_prec , { 3 , 1 }, scale , max_bias )); 10215test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 - 1 , ne1 - 1 , 1 , 1 }, mask , sinks , m_prec , { 2 , 3 }, scale , max_bias )); 10216} 10217} 10218} else { 10219/* The precision of mask here doesn't matter as boolean mask is false */ 10220test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 , ne1 , 1 , 1 }, mask , sinks , GGML_TYPE_F32 , { 1 , 1 }, scale , max_bias )); 10221test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { ne0 - 1 , ne1 - 1 , 1 , 1 }, mask , sinks , GGML_TYPE_F32 , { 1 , 1 }, scale , max_bias )); 10222} 10223} 10224} 10225} 10226} 10227// inplace tests 10228test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 16 , 2 , 32 , 1 }, mask , sinks , GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 0.0f , true)); 10229test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 16 , 2 , 32 , 1 }, mask , sinks , GGML_TYPE_F16 , { 1 , 1 }, 0.1f , 0.0f , true)); 10230} 10231} 10232test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 16 , 2 , 32 , 1 }, true, true, GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 0.0f )); 10233test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 16 , 2 , 32 , 1 }, true, false, GGML_TYPE_F16 , { 1 , 1 }, 0.1f , 0.0f )); 10234test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 16 , 2 , 32 , 1 }, false, true, GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 0.0f )); 10235test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 32 , 2 , 32 , 1 }, true, true, GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 0.0f )); 10236test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 32 , 2 , 32 , 1 }, true, false, GGML_TYPE_F16 , { 1 , 1 }, 0.1f , 0.0f )); 10237test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 32 , 2 , 32 , 1 }, true, true, GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 8.0f )); 10238test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 32 , 2 , 32 , 1 }, true, true, GGML_TYPE_F16 , { 1 , 1 }, 0.1f , 8.0f )); 10239 10240test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 200001 , 2 , 3 , 1 }, true, true, GGML_TYPE_F32 , { 1 , 1 }, 0.1f , 8.0f )); 10241test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 200001 , 2 , 3 , 1 }, true, true, GGML_TYPE_F16 , { 1 , 1 }, 0.1f , 8.0f )); 10242test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 200000 , 1 , 1 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 10243test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 200000 , 4 , 1 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 10244test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 643251 , 3 , 1 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 10245 10246for (float max_bias : { 0.0f , 8.0f }) { 10247for (float scale : { 1.0f , 0.1f }) { 10248for (int64_t ne0 : { 16 , 1024 }) { 10249for (int64_t ne1 : { 16 , 1024 }) { 10250test_cases . emplace_back ( new test_soft_max_back( GGML_TYPE_F32 , { ne0 , ne1 , 1 , 1 }, scale , max_bias )); 10251test_cases . emplace_back ( new test_soft_max_back( GGML_TYPE_F32 , { ne0 - 1 , ne1 - 1 , 1 , 1 }, scale , max_bias )); 10252test_cases . emplace_back ( new test_soft_max_back( GGML_TYPE_F32 , { ne0 , ne1 , 2 , 3 }, scale , max_bias )); 10253} 10254} 10255} 10256} 10257 10258for (bool fw : {true, false}) { // fw == forward 10259bool all = true; 10260 10261for (float fs : { 1.0f , 1.4245f }) { 10262for (float ef : { 0.0f , 0.7465f }) { 10263for (float af : { 1.0f , 1.4245f }) { 10264for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10265for (bool ff : {false, true}) { // freq_factors 10266for (float v : { 0 , 1 }) { 10267test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); // llama 7B 10268 10269if ( all ) { 10270test_cases . emplace_back ( new test_rope( type , { 128 , 40 , 2 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); // llama 13B 10271test_cases . emplace_back ( new test_rope( type , { 128 , 52 , 2 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); // llama 30B 10272test_cases . emplace_back ( new test_rope( type , { 128 , 64 , 2 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); // llama 65B 10273test_cases . emplace_back ( new test_rope( type , { 16 , 16 , 8192 , 1 }, 16 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); 10274} 10275 10276if ( all ) { 10277test_cases . emplace_back ( new test_rope( type , { 64 , 1 , 2 , 1 }, 64 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (falcon 7B) 10278test_cases . emplace_back ( new test_rope( type , { 64 , 71 , 2 , 1 }, 64 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (falcon 7B) 10279test_cases . emplace_back ( new test_rope( type , { 64 , 8 , 2 , 1 }, 64 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (falcon 40B) 10280 10281test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 2 , 1 }, 20 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); 10282test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 2 , 1 }, 32 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); 10283test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 4 , 1 }, 32 , GGML_ROPE_TYPE_NORMAL , 512 , fs , ef , af , ff , v , fw )); 10284 10285test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 2 , 1 }, 20 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (stablelm) 10286test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 2 , 1 }, 32 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (phi-2) 10287test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 4 , 1 }, 32 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (phi-2) 10288test_cases . emplace_back ( new test_rope( type , { 16 , 16 , 8192 , 1 }, 16 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); 10289} 10290 10291if ( all ) { 10292test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 128 , GGML_ROPE_TYPE_MROPE , 512 , fs , ef , af , ff , v , fw )); // rope_multi,m-rope (qwen2vl 2B) 10293test_cases . emplace_back ( new test_rope( type , { 128 , 28 , 2 , 1 }, 128 , GGML_ROPE_TYPE_MROPE , 512 , fs , ef , af , ff , v , fw )); // rope_multi,m-rope (qwen2vl 7B) 10294test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 20 , GGML_ROPE_TYPE_MROPE , 512 , fs , ef , af , ff , v , fw )); 10295test_cases . emplace_back ( new test_rope( type , { 128 , 28 , 2 , 1 }, 32 , GGML_ROPE_TYPE_MROPE , 512 , fs , ef , af , ff , v , fw )); 10296test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 128 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); // rope_multi,imrope (qwen3vl 2B) 10297test_cases . emplace_back ( new test_rope( type , { 128 , 28 , 2 , 1 }, 128 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); // rope_multi,imrope (qwen3vl 7B) 10298test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 20 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); 10299test_cases . emplace_back ( new test_rope( type , { 128 , 28 , 2 , 1 }, 32 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); 10300test_cases . emplace_back ( new test_rope( type , { 80 , 16 , 2 , 1 }, 80 , GGML_ROPE_TYPE_VISION , 512 , fs , ef , af , ff , v , fw )); // rope_multi,m-rope (qwen2vl ViT) 10301test_cases . emplace_back ( new test_rope( type , { 128 , 16 , 2 , 1 }, 128 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); // rope_multi,m-rope (qwen3vl) 10302test_cases . emplace_back ( new test_rope( type , { 16 , 16 , 8192 , 1 }, 16 , GGML_ROPE_TYPE_IMROPE , 512 , fs , ef , af , ff , v , fw )); 10303} 10304 10305test_cases . emplace_back ( new test_rope( type , { 64 , 128 , 2 , 1 }, 64 , GGML_ROPE_TYPE_NEOX , 512 , fs , ef , af , ff , v , fw )); // neox (falcon 40B) 10306} 10307 10308// build_rope_2d-style: ROPE on a non-contiguous view 10309// that starts at a non-zero offset along dim 0 10310// (e.g. gemma4v vision second-half view). 10311for (int rmode : { GGML_ROPE_TYPE_NORMAL , GGML_ROPE_TYPE_NEOX , GGML_ROPE_TYPE_MROPE , GGML_ROPE_TYPE_IMROPE , GGML_ROPE_TYPE_VISION }) { 10312test_cases . emplace_back ( new test_rope( type , { 36 , 16 , 2457 , 1 }, 36 , rmode , 512 , fs , ef , af , ff , 2 , fw )); 10313} 10314} 10315 10316all = false; 10317} 10318} 10319} 10320} 10321} 10322 10323// single inplace test per type/mode/ff 10324for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10325for (int mode : { GGML_ROPE_TYPE_NORMAL , GGML_ROPE_TYPE_NEOX , GGML_ROPE_TYPE_MROPE , GGML_ROPE_TYPE_IMROPE , GGML_ROPE_TYPE_VISION }) { 10326for (bool ff : {false, true}) { 10327test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 128 , mode , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 0 , true, true)); 10328test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 128 , mode , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 1 , true, true)); 10329test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 3 }, 128 , mode , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 1 , true, true)); 10330} 10331} 10332} 10333 10334// rotated dims window at an offset (ggml_rope_set_offset), not supported for vision mode 10335for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10336for (bool fw : {true, false}) { // fw == forward 10337for (bool ff : {false, true}) { 10338test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 32 , GGML_ROPE_TYPE_NORMAL , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 0 , fw , false, 32 )); 10339test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 32 , GGML_ROPE_TYPE_NEOX , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 0 , fw , false, 32 )); 10340test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 24 , GGML_ROPE_TYPE_MROPE , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 0 , fw , false, 32 )); 10341test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 2 , 1 }, 24 , GGML_ROPE_TYPE_IMROPE , 512 , 1.4245f , 0.7465f , 1.4245f , ff , 0 , fw , false, 32 )); 10342} 10343} 10344// inplace with an offset 10345test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 2 , 1 }, 32 , GGML_ROPE_TYPE_NEOX , 512 , 1.4245f , 0.7465f , 1.4245f , false, 0 , true, true, 32 )); 10346} 10347 10348// Real-model RoPE: F32 forward, packed Q, 512-token prefill. 10349test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 8 , 512 , 1 }, 64 , GGML_ROPE_TYPE_IMROPE , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // qwen3.5 0.8B 10350test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 16 , 512 , 1 }, 64 , GGML_ROPE_TYPE_IMROPE , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // qwen3.5 4B 10351test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 8 , 512 , 1 }, 256 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // gemma4 E2B sliding 10352test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 512 , 8 , 512 , 1 }, 128 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , true, 0 , true)); // gemma4 E4B global 10353 10354for (int v : { 0 , 1 , 2 , 3 }) { 10355for (int dim : { 0 , 1 , 2 , 3 , }) { 10356test_cases . emplace_back ( new test_concat( GGML_TYPE_F32 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10357test_cases . emplace_back ( new test_concat( GGML_TYPE_F16 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10358test_cases . emplace_back ( new test_concat( GGML_TYPE_BF16 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10359test_cases . emplace_back ( new test_concat( GGML_TYPE_I8 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10360test_cases . emplace_back ( new test_concat( GGML_TYPE_I16 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10361test_cases . emplace_back ( new test_concat( GGML_TYPE_I32 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10362test_cases . emplace_back ( new test_concat( GGML_TYPE_I64 , { 11 , 12 , 13 , 14 }, 7 , dim , v )); 10363} 10364} 10365 10366for (ggml_type type_a : { GGML_TYPE_Q4_0 , GGML_TYPE_Q4_1 , GGML_TYPE_Q5_0 , GGML_TYPE_Q5_1 , GGML_TYPE_Q8_0 }) { 10367for (int v : { 0 , 4 , 8 , 12 }) { 10368for (int dim : { 0 , 1 , 2 , 3 , }) { 10369test_cases . emplace_back ( new test_concat( type_a , { 128 , 12 , 13 , 14 }, dim == 0 ? 256 : 7 , dim , v )); 10370} 10371} 10372} 10373 10374for (ggml_sort_order order : { GGML_SORT_ORDER_ASC , GGML_SORT_ORDER_DESC }) { 10375for (uint32_t i = 4 ; i <= 1024 * 1024 ; i *= 2 ) { 10376test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { i - 1 , 1 , 1 , 1 })); 10377test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { i , 1 , 1 , 1 })); 10378} 10379test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 16 , 10 , 10 , 10 }, order )); 10380test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 60 , 10 , 10 , 10 }, order )); // qwen 10381test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 1023 , 2 , 1 , 3 }, order )); 10382test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 1024 , 2 , 1 , 3 }, order )); 10383test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 1025 , 2 , 1 , 3 }, order )); 10384test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 1025 , 256 , 1 , 1 }, order )); // test ceildiv in CUDA's CUB's DeviceSegmentedSort 10385test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 2047 , 2 , 1 , 3 }, order )); 10386test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 2048 , 2 , 1 , 3 }, order )); 10387test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 2049 , 2 , 1 , 3 }, order )); 10388test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 2 , 8 , 8192 , 1 }, order )); // bailingmoe2 (group selection) 10389test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 2048 , 512 , 1 , 1 }, order )); // test CUDA dispatching to radix sort for nrows > = 1 in graph mode 10390} 10391 10392for (int n = 1 ; n < 5 ; ++ n ) { 10393for (int k = 1 ; k <= n ; ++ k ) { 10394test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { n , 2 , 1 , 3 }, k , true)); 10395} 10396} 10397for (int i = 0 ; i < 20 ; ++ i ) { 10398for (int k : { 1 , 2 , 3 , 7 , 15 , 100 , 500 , 1023 , 9999 }) { 10399if ( k <= 1 << i ) { 10400test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , {( 1 << i ), 1 , 1 , 1 }, k )); 10401test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , {( 1 << i ) + 11 , 1 , 2 , 1 }, k )); 10402test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , {( 1 << i ) + 11 , 1 , 2 , 1 }, k , true)); 10403} 10404} 10405} 10406for (int k : { 4 , 8 , 16 , 32 }) { 10407for (int nrows : { 1 , 8 , 16 }) { 10408test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 202048 , nrows , 1 , 1 }, k )); 10409test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 151936 , nrows , 1 , 1 }, k )); 10410test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 8192 , nrows , 1 , 1 }, k )); 10411test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 8193 , nrows , 1 , 1 }, k )); 10412test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 8192 , nrows , 1 , 1 }, k , true)); 10413test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 202048 , nrows , 1 , 1 }, k , true)); 10414} 10415} 10416 10417for (int k : { 1 , 2 , 3 , 7 , 15 }) { 10418test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 16 , 10 , 10 , 10 }, k )); 10419test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 60 , 10 , 10 , 10 }, k )); 10420test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 1023 , 2 , 1 , 3 }, k )); 10421test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 1024 , 2 , 1 , 3 }, k )); 10422test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 1025 , 2 , 1 , 3 }, k )); 10423test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 16384 , 1 , 1 , 1 }, k )); 10424test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 2047 , 2 , 1 , 3 }, k )); 10425test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 2048 , 2 , 1 , 3 }, k )); 10426test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 2049 , 2 , 1 , 3 }, k )); 10427} 10428 10429// Large-k, including multi-row and ties (qwen4exp) 10430test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 1024 , 1 , 1 , 1 }, 1024 )); 10431test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 2048 , 2 , 1 , 1 }, 1024 )); 10432test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 4096 , 1 , 1 , 1 }, 2048 )); 10433test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 8192 , 2 , 1 , 1 }, 2051 )); 10434test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 33024 , 1 , 1 , 1 }, 2051 )); 10435test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 33024 , 4 , 1 , 1 }, 2051 )); 10436test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 8192 , 2 , 1 , 1 }, 2051 , true)); 10437test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 33024 , 4 , 1 , 1 }, 2051 , true)); 10438 10439// qwen4exp QSA indexer top-k fusion (get_rows + f16 mask + top_k) 10440test_cases . emplace_back ( new test_topk_qsa( 512 , 2048 , 1 , 1 , 1500 )); 10441test_cases . emplace_back ( new test_topk_qsa( 512 , 2048 , 2 , 1 , 1500 )); 10442test_cases . emplace_back ( new test_topk_qsa( 256 , 2048 , 4 , 2 , 2000 )); 10443test_cases . emplace_back ( new test_topk_qsa( 64 , 256 , 2 , 1 , 200 )); // small k: unfused fallback 10444 10445// exhaustive top_k tests 10446//for (int i = 1; i < 9999; ++i) { 10447// test_cases.emplace_back(new test_top_k(GGML_TYPE_F32, {i, 2, 1, 3}, rand() % i + 1)); 10448//} 10449 10450for (ggml_scale_mode mode : { GGML_SCALE_MODE_NEAREST , GGML_SCALE_MODE_BILINEAR , GGML_SCALE_MODE_BICUBIC , ggml_scale_mode ( GGML_SCALE_MODE_BILINEAR | GGML_SCALE_FLAG_ANTIALIAS )}) { 10451test_cases . emplace_back ( new test_upscale( GGML_TYPE_F32 , { 512 , 512 , 3 , 2 }, 2 , mode )); 10452test_cases . emplace_back ( new test_upscale( GGML_TYPE_F32 , { 512 , 512 , 3 , 2 }, 2 , mode , true)); 10453test_cases . emplace_back ( new test_interpolate( GGML_TYPE_F32 , { 2 , 5 , 7 , 11 }, { 5 , 7 , 11 , 13 }, mode )); 10454test_cases . emplace_back ( new test_interpolate( GGML_TYPE_F32 , { 5 , 7 , 11 , 13 }, { 2 , 5 , 7 , 11 }, mode )); 10455} 10456for (ggml_scale_mode mode : { GGML_SCALE_MODE_BILINEAR , GGML_SCALE_MODE_BICUBIC }) { 10457test_cases . emplace_back ( new test_interpolate( GGML_TYPE_F32 , { 2 , 5 , 7 , 11 }, { 5 , 7 , 11 , 13 }, ( ggml_scale_mode )( mode | GGML_SCALE_FLAG_ALIGN_CORNERS ))); 10458test_cases . emplace_back ( new test_interpolate( GGML_TYPE_F32 , { 1 , 4 , 3 , 2 }, { 2 , 8 , 3 , 2 }, ( ggml_scale_mode )( mode | GGML_SCALE_FLAG_ALIGN_CORNERS ))); 10459test_cases . emplace_back ( new test_interpolate( GGML_TYPE_F32 , { 4 , 1 , 3 , 2 }, { 1 , 1 , 3 , 2 }, ( ggml_scale_mode )( mode | GGML_SCALE_FLAG_ALIGN_CORNERS ))); 10460} 10461 10462test_cases . emplace_back ( new test_sum()); 10463test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, { 0 , 2 , 1 , 3 })); // row-contiguous but non-contiguous 10464test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, { 0 , 3 , 2 , 1 })); 10465test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, { 0 , 1 , 3 , 2 })); 10466test_cases . emplace_back ( new test_mean()); 10467test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 33 , 1 , 1 , 1 })); 10468test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 33 , 256 , 1 , 1 })); 10469test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 32769 , 1 , 1 , 1 })); 10470test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 32 , 1 , 1 , 1 })); 10471test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 32 , 256 , 1 , 1 })); 10472test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 32768 , 1 , 1 , 1 })); 10473test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 33 , 1 , 1 , 1 })); 10474test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 33 , 1024 , 1 , 1 })); 10475test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 33 , 256 , 1 , 1 })); 10476test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , { 33 , 256 , 1 , 1 }, { 1 , 0 , 2 , 3 })); // sum dst not-contiguous 10477test_cases . emplace_back ( new test_sum_rows()); 10478test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, true, false)); 10479test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, false, true)); 10480test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 11 , 5 , 6 , 3 }, true, true)); 10481test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 16 , 5 , 6 , 3 }, true, false)); 10482test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 16 , 5 , 6 , 3 }, false, true)); 10483test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 16 , 5 , 6 , 3 }, true, true)); 10484test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 33 , 1 , 1 , 1 })); 10485test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 33 , 1024 , 1 , 1 })); 10486test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , { 33 , 256 , 1 , 1 })); 10487test_cases . emplace_back ( new test_group_norm( GGML_TYPE_F32 , { 64 , 64 , 320 , 1 })); 10488test_cases . emplace_back ( new test_group_norm( GGML_TYPE_F32 , { 9 , 9 , 1280 , 1 })); 10489test_cases . emplace_back ( new test_group_norm_mul_add( GGML_TYPE_F32 , { 64 , 64 , 320 , 1 })); 10490test_cases . emplace_back ( new test_group_norm_mul_add( GGML_TYPE_F32 , { 9 , 9 , 1280 , 1 })); 10491test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 1 , 1 }, { 256 , 16 , 1 , 1 }, -1 )); 10492test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 256 , 16 , 2 , 3 }, -1 )); 10493test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 128 , 16 , 2 , 3 }, -1 )); 10494test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 256 , 16 , 2 , 3 }, 1 )); 10495test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 128 , 16 , 2 , 3 }, 2 )); 10496test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 64 , 16 , 2 , 3 }, 3 )); 10497 10498test_cases . emplace_back ( new test_pad()); 10499test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 33 , 17 , 2 , 1 }, 4 , 3 , true)); // circular 10500test_cases . emplace_back ( new test_pad_ext()); 10501test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1024 , 1 , 1 , 1 }, 1 , 0 , false)); 10502test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1024 , 2 , 1 , 1 }, 1 , 0 , false)); 10503test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1024 , 16 , 1 , 1 }, 0 , 1 , false)); 10504test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1023 , 1 , 1 , 1 }, 1 , 0 , false)); 10505test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1023 , 8 , 1 , 1 }, 1 , 0 , false)); 10506test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1025 , 1 , 1 , 1 }, 1 , 0 , false)); 10507test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 1025 , 8 , 1 , 1 }, 1 , 0 , false)); 10508test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 2048 , 1 , 1 , 1 }, 1 , 0 , false)); 10509test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 2048 , 4 , 1 , 1 }, 1 , 0 , false)); 10510test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 2049 , 1 , 1 , 1 }, 1 , 0 , false)); 10511test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 100 , 1 , 1 , 1 }, 100 , 0 , false)); 10512test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 100 , 1 , 1 , 1 }, 0 , 100 , false)); 10513test_cases . emplace_back ( new test_pad( GGML_TYPE_F32 , { 100 , 100 , 1 , 1 }, 50 , 50 , false)); 10514 10515test_cases . emplace_back ( new test_pad_reflect_1d()); 10516test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 3000 , 384 , 4 , 1 })); 10517test_cases . emplace_back ( new test_roll()); 10518test_cases . emplace_back ( new test_roll( 3 , -2 , 1 , -1 , true)); 10519test_cases . emplace_back ( new test_arange()); 10520test_cases . emplace_back ( new test_arange( GGML_TYPE_F32 , 0.0f , 1048576.0f , 1.0f )); 10521test_cases . emplace_back ( new test_timestep_embedding()); 10522test_cases . emplace_back ( new test_leaky_relu()); 10523 10524test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 10 , 5 , 4 , 3 })); 10525test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 127 , 5 , 4 , 3 })); 10526test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 128 , 5 , 4 , 3 })); 10527test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 128 , 128 , 4 , 4 })); 10528test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 255 , 5 , 4 , 3 })); 10529test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 256 , 5 , 4 , 3 })); 10530test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 511 , 5 , 4 , 3 })); 10531test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 512 , 5 , 4 , 3 })); 10532test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 1023 , 5 , 4 , 3 })); 10533test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 1024 , 5 , 4 , 3 })); 10534test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 2047 , 5 , 4 , 3 })); 10535test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 2048 , 5 , 4 , 3 })); 10536test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 201 * 1204 , 1 , 1 , 1 })); 10537test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 312 * 1205 , 1 , 1 , 1 })); 10538test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 20481 , 4 , 1 , 1 })); 10539 10540test_cases . emplace_back ( new test_xielu()); 10541test_cases . emplace_back ( new test_xielu( GGML_TYPE_F16 )); 10542test_cases . emplace_back ( new test_xielu( GGML_TYPE_F32 , { 512 , 16 , 1 , 1 })); 10543test_cases . emplace_back ( new test_xielu( GGML_TYPE_F16 , { 512 , 16 , 1 , 1 })); 10544 10545test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_LOWER )); 10546test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_LOWER_DIAG )); 10547test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_UPPER )); 10548test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_UPPER_DIAG )); 10549 10550test_cases . emplace_back ( new test_fill( 0.0f )); 10551test_cases . emplace_back ( new test_fill( 2.0f , GGML_TYPE_F32 , { 303 , 207 , 11 , 3 })); 10552test_cases . emplace_back ( new test_fill( -152.0f , GGML_TYPE_F32 , { 800 , 600 , 4 , 4 })); 10553test_cases . emplace_back ( new test_fill( 3.5f , GGML_TYPE_F32 , { 2048 , 512 , 2 , 2 })); 10554 10555test_cases . emplace_back ( new test_diag()); 10556test_cases . emplace_back ( new test_diag( GGML_TYPE_F32 , { 79 , 1 , 19 , 13 })); 10557test_cases . emplace_back ( new test_diag( GGML_TYPE_F32 , { 256 , 1 , 8 , 16 })); 10558 10559test_cases . emplace_back ( new test_solve_tri()); 10560test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 11 , 11 , 1 , 1 }, { 5 , 11 , 1 , 1 })); 10561test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 17 , 17 , 2 , 4 }, { 9 , 17 , 2 , 4 })); 10562test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 30 , 30 , 7 , 1 }, { 8 , 30 , 7 , 1 })); 10563test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 42 , 42 , 5 , 2 }, { 10 , 42 , 5 , 2 })); 10564test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 2 , 2 }, { 10 , 64 , 2 , 2 })); 10565test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 2 , 2 }, { 64 , 64 , 2 , 2 })); 10566test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 79 , 79 , 5 , 3 }, { 417 , 79 , 5 , 3 })); 10567test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 2 }, { 32 , 128 , 4 , 2 })); 10568test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 2 , 8 }, { 80 , 80 , 2 , 8 })); 10569test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 2 , 8 }, { 79 , 80 , 2 , 8 })); 10570test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 2 , 8 }, { 81 , 80 , 2 , 8 })); 10571test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 8 , 8 }, { 80 , 80 , 8 , 8 })); 10572test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 8 , 8 }, { 79 , 80 , 8 , 8 })); 10573test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 80 , 80 , 8 , 8 }, { 81 , 80 , 8 , 8 })); 10574test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 84 , 84 , 4 , 4 }, { 32 , 84 , 4 , 4 })); 10575test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 95 , 95 , 8 , 8 }, { 40 , 95 , 8 , 8 })); 10576test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 100 , 100 , 4 , 4 }, { 41 , 100 , 4 , 4 })); 10577test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 4 }, { 31 , 128 , 4 , 4 })); 10578test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 4 }, { 32 , 128 , 4 , 4 })); 10579test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 3 , 4 }, { 32 , 128 , 3 , 4 })); 10580test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 1 }, { 32 , 128 , 4 , 1 })); 10581test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 4 , 4 }, { 200 , 64 , 4 , 4 })); 10582test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 4 , 4 }, { 384 , 64 , 4 , 4 })); 10583 10584for (int tfrm : { 0 , 1 , 2 }) { 10585for (bool circular : {false, true}) { 10586test_cases . emplace_back ( new test_pad_ext( GGML_TYPE_F32 , { 512 , 512 , 1 , 1 }, 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , tfrm , circular )); 10587test_cases . emplace_back ( new test_pad_ext( GGML_TYPE_F32 , { 11 , 22 , 33 , 44 }, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , tfrm , circular )); 10588} 10589} 10590 10591// prefill-shaped cases with long KV (nb >= 32, kv >= 1024): covers the 10592// XMX/GEMM-accelerated SYCL FA path which only activates for these shapes. 10593for (int kv : { 1024 , 2048 , }) { 10594for (int hs : { 64 , 128 , 256 , }) { 10595for (int nb : { 32 , 64 , }) { 10596for (ggml_type type_KV : { GGML_TYPE_F16 , GGML_TYPE_Q8_0 , GGML_TYPE_Q4_0 , }) { 10597test_cases . emplace_back ( new test_flash_attn_ext( hs , hs , 8 , { 4 , 1 }, kv , nb , true, false, 0 , 0 , GGML_PREC_F32 , type_KV , type_KV )); 10598} 10599} 10600} 10601} 10602 10603for (int hsk : { 40 , 64 , 72 , 80 , 96 , 128 , 192 , 256 , 320 , 512 , 576 }) { 10604for (int hsv : { 40 , 64 , 72 , 80 , 96 , 128 , 192 , 256 , 512 }) { 10605if ( hsk != 192 && hsk != 320 && hsk != 576 && hsk != hsv ) continue ; 10606if ( hsk == 192 && ( hsv != 128 && hsv != 192 )) continue ; 10607if ( hsk == 576 && hsv != 512 ) continue ; // DeepSeek MLA 10608if ( hsk == 320 && hsv != 256 ) continue ; // Mistral4 MLA 10609 10610for (bool mask : { true, false } ) { 10611for (bool sinks : { true, false } ) { 10612for (float max_bias : { 0.0f , 8.0f }) { 10613if (! mask && max_bias > 0.0f ) continue ; 10614for (float logit_softcap : { 0.0f , 10.0f }) { 10615if ( hsk != 128 && logit_softcap != 0.0f ) continue ; 10616for (int nh : { 1 , 4 }) { 10617if ( nh == 1 && hsk != 320 && hsk != 576 ) continue ; 10618for (int nr3 : { 1 , 3 , }) { 10619if ( hsk > 64 && nr3 > 1 ) continue ; // skip broadcast for large head sizes 10620for (int nr2 : { 1 , 4 , 8 , 12 , 16 , 20 , 32 }) { 10621if ( nr2 == 8 && hsk != 192 ) continue ; 10622if ( nr2 == 12 && hsk != 128 ) continue ; 10623if ( nr2 == 16 && hsk != 192 ) continue ; 10624if ( nr2 == 20 && ( nh != 1 || hsk != 576 )) continue ; 10625if ( nr2 == 32 && ( nh != 1 || hsk != 320 )) continue ; 10626//for (int kv : { 1, 17, 31, 33, 61, 113, 65, 127, 129, 130, 255, 260, 371, 380, 407, 512, 1024, }) { 10627for (int kv : { 113 , 512 , 1024 , }) { 10628if ( nr2 != 1 && kv != 512 ) continue ; 10629for (int nb : { 1 , 3 , 32 , 75 , }) { 10630for (ggml_prec prec : { GGML_PREC_F32 , GGML_PREC_DEFAULT }) { 10631if ( hsk != 128 && prec == GGML_PREC_DEFAULT ) continue ; 10632for (ggml_type type_KV : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_Q8_0 , GGML_TYPE_Q5_1 , GGML_TYPE_Q5_0 , GGML_TYPE_Q4_1 , GGML_TYPE_Q4_0 , GGML_TYPE_IQ4_NL }) { 10633if ( type_KV != GGML_TYPE_F16 && hsk != 64 && hsk != 72 ) continue ; 10634// DeepSeek MLA: the V cache is a sub-view of the K cache 10635const bool v_is_view_of_k = hsk == 576 ; 10636test_cases . emplace_back ( new test_flash_attn_ext( 10637hsk , hsv , nh , { nr2 , nr3 }, kv , nb , mask , sinks , max_bias , logit_softcap , prec , type_KV , type_KV , { 0 , 1 , 2 , 3 }, true, v_is_view_of_k )); 10638// run fewer test cases permuted 10639if ( mask == true && max_bias == 0.0f && logit_softcap == 0 && kv == 512 ) { 10640test_cases . emplace_back ( new test_flash_attn_ext( 10641hsk , hsv , nh , { nr2 , nr3 }, kv , nb , mask , sinks , max_bias , logit_softcap , prec , type_KV , type_KV , { 0 , 2 , 1 , 3 }, true, v_is_view_of_k )); 10642} 10643} 10644} 10645} 10646} 10647} 10648} 10649} 10650} 10651} 10652} 10653} 10654} 10655} 10656 10657// mixed quant and Q1_0 test cases 10658test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q4_0 )); 10659test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_F16 )); 10660test_cases . emplace_back ( new test_flash_attn_ext( 72 , 72 , 4 , { 1 , 1 }, 96 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_Q8_0 )); 10661test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 96 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F32 )); 10662test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 4 , { 1 , 1 }, 256 , 1 , false, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_Q4_0 )); 10663test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 4 , { 1 , 1 }, 96 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q1_0 , GGML_TYPE_Q1_0 )); 10664test_cases . emplace_back ( new test_flash_attn_ext( 128 , 64 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q1_0 , GGML_TYPE_Q4_0 )); 10665test_cases . emplace_back ( new test_flash_attn_ext( 64 , 128 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_Q1_0 )); 10666test_cases . emplace_back ( new test_flash_attn_ext( 128 , 64 , 4 , { 1 , 1 }, 64 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q1_0 , GGML_TYPE_F16 )); 10667test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 4 , { 1 , 1 }, 96 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q2_0 , GGML_TYPE_Q2_0 )); 10668test_cases . emplace_back ( new test_flash_attn_ext( 128 , 64 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q2_0 , GGML_TYPE_Q4_0 )); 10669test_cases . emplace_back ( new test_flash_attn_ext( 64 , 128 , 4 , { 1 , 1 }, 128 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_Q2_0 )); 10670test_cases . emplace_back ( new test_flash_attn_ext( 128 , 64 , 4 , { 1 , 1 }, 64 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q2_0 , GGML_TYPE_F16 )); 10671 10672// q8_0 KV cases: decode and prompt batches, KV pad, permuted KV, feature flags, and long context 10673test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 113 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 10674test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 1024 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 10675test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 1024 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 2 , 1 , 3 })); 10676test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 2 }, 1025 , 1 , true, true, 8 , 30 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 10677test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 1025 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 2 , 1 , 3 })); 10678test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 16384 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 10679 10680// MLA shape: the V cache is a sub-view of the K cache, with quantized KV 10681test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 8 , 1 }, 113 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, true)); 10682test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 8 , 1 }, 1024 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, true)); 10683test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 8 , 1 }, 1024 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, true)); 10684 10685// Sparse mask hint: supported decode/prefill layouts and dense fallbacks. 10686test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10687test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 2 }, 4096 , 3 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 768 )); 10688test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 512 )); 10689test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 2 }, 4096 , 2 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 768 )); 10690test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 2304 )); 10691test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 1 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10692test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10693 10694test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 4 , true, false, 8.0f , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10695 10696// sparse mask with large batch size 10697test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10698test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 2048 )); 10699test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 512 )); 10700test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 2048 )); 10701test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10702test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10703test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 2048 )); 10704 10705// sparse mask + quantized cache 10706test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10707test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 1 , { 8 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, false, 512 )); 10708 10709// more V-is-sub-view-of-K cases: other head shapes, and full views with equal head sizes 10710test_cases . emplace_back ( new test_flash_attn_ext( 320 , 256 , 1 , { 32 , 1 }, 512 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true)); 10711test_cases . emplace_back ( new test_flash_attn_ext( 192 , 128 , 4 , { 8 , 1 }, 512 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true)); 10712test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 8 , { 4 , 1 }, 512 , 8 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true)); 10713test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 512 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, true, true)); 10714 10715// large-KV F16 cases (Qwen3.6-27B geometry and a llama-class control): the upstream matrix 10716// stops at kv=1024, blind to long-context FA bugs (e.g. the oneDNN SDPA ordering race on BMG). 10717for (int64_t kv : { 4096 , 16384 }) { 10718test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, kv , 512 , true, false, 0 , 0 , 10719GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10720test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 8 , { 4 , 1 }, kv , 512 , true, false, 0 , 0 , 10721GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10722} 10723 10724test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 512 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10725test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 4096 , 64 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10726test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 4096 , 16 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10727test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 2 , 1 }, 4096 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10728test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 4 , 1 }, 4096 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10729test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 12 , 1 }, 4096 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10730 10731// dense-allocated (non-view) quant K/V at batch >= 64, in cache and native layouts 10732test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 512 , 75 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 2 , 1 , 3 }, false)); 10733test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 4 , 1 }, 512 , 75 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 2 , 1 , 3 }, false)); 10734test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 1024 , 75 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 2 , 1 , 3 }, false)); 10735test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 4 , { 1 , 1 }, 512 , 75 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 , { 0 , 1 , 2 , 3 }, false)); 10736 10737// FLASH_ATTN_EXT MMA: non-pow2 head size and MLA K/V view. 10738test_cases . emplace_back ( new test_flash_attn_ext( 192 , 128 , 8 , { 8 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10739test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 20 , 1 }, 512 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true)); 10740 10741// FLASH_ATTN_EXT MMA, swizzled K/V tiles, power-of-two stride: nbatch_K2 = 32, 64, 128, 256. 10742test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 4096 , 4 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10743test_cases . emplace_back ( new test_flash_attn_ext( 128 , 128 , 8 , { 4 , 1 }, 4096 , 8 , true, true, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10744test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 2 , 1 }, 1024 , 32 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10745test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 4 , { 2 , 1 }, 1024 , 4 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 10746 10747test_cases . emplace_back ( new test_cross_entropy_loss ( GGML_TYPE_F32 , { 10 , 5 , 4 , 3 })); 10748test_cases . emplace_back ( new test_cross_entropy_loss ( GGML_TYPE_F32 , { 30000 , 1 , 1 , 1 })); 10749test_cases . emplace_back ( new test_cross_entropy_loss_back( GGML_TYPE_F32 , { 10 , 5 , 4 , 3 })); 10750test_cases . emplace_back ( new test_cross_entropy_loss_back( GGML_TYPE_F32 , { 30000 , 1 , 1 , 1 })); 10751 10752test_cases . emplace_back ( new test_opt_step_adamw( GGML_TYPE_F32 , { 10 , 5 , 4 , 3 })); 10753test_cases . emplace_back ( new test_opt_step_sgd( GGML_TYPE_F32 , { 10 , 5 , 4 , 3 })); 10754 10755for (ggml_type type : base_types ) { 10756for (bool with_gate : {false, true}) { 10757for (bool use_id : {false, true}) { 10758for (bool b : {false, true}) { 10759if (! use_id && b ) { 10760continue ; 10761} 10762for (bool with_bias : {false, true}) { 10763if (! with_gate && ! with_bias ) { 10764continue ; 10765} 10766for (ggml_glu_op glu_op : { GGML_GLU_OP_SWIGLU , GGML_GLU_OP_GEGLU , GGML_GLU_OP_SWIGLU_CLAMP }) { 10767if (! with_bias && glu_op == GGML_GLU_OP_SWIGLU_OAI ) { 10768continue ; 10769} 10770if (! with_gate && glu_op != GGML_GLU_OP_SWIGLU ) { 10771continue ; 10772} 10773for (bool with_lane_scale : {false, true}) { 10774if ( with_lane_scale && type != GGML_TYPE_NVFP4 ) { 10775continue ; 10776} 10777test_cases . emplace_back ( new test_mul_mat_vec_fusion( type , glu_op , 1 , 32 , 256 , 10778use_id , 16 , 8 , b , with_bias , with_gate , with_lane_scale )); 10779test_cases . emplace_back ( new test_mul_mat_vec_fusion( type , glu_op , 1 , 32 , 256 , 10780use_id , 16 , 8 , b , with_bias , with_gate , with_lane_scale , { 1 , 1 })); 10781// multi-token batches (spec decoding) 10782for (int64_t m_batch : { 2 , 4 , 8 }) { 10783test_cases . emplace_back ( new test_mul_mat_vec_fusion( type , glu_op , m_batch , 32 , 256 , 10784use_id , 16 , 8 , b , with_bias , with_gate , with_lane_scale , { 1 , 1 })); 10785} 10786} 10787} 10788} 10789} 10790} 10791} 10792} 10793 10794for (bool b : {false, true}) { 10795test_cases . emplace_back ( new test_mul_mat_vec_fusion( GGML_TYPE_IQ2_S , GGML_GLU_OP_SWIGLU_CLAMP , 1 , 32 , 256 , 10796true, 16 , 8 , b , false, true, false)); 10797} 10798 10799// Fused row-pair coverage: minimum rows, an even pair, and an odd tail. 10800// TODO: the max_nmse_err() for these cases is not estimated correctly causing sporadic false failures. 10801//for (ggml_glu_op glu_op : { GGML_GLU_OP_SWIGLU, GGML_GLU_OP_GEGLU }) { 10802// for (int64_t m_batch : { 2, 3, 4 }) { 10803// for (int64_t rows : { 1, 2, 3 }) { 10804// test_cases.emplace_back(new test_mul_mat_vec_fusion(GGML_TYPE_Q4_K, glu_op, m_batch, rows, 256, 10805// false, 16, 8, false, false, true, false, { 1, 1 })); 10806// } 10807// } 10808//} 10809 10810// Both sides of the same row-count boundary as above, on the fused path. 10811for (int64_t rows : { 6271 , 6272 , 6273 }) { 10812test_cases . emplace_back ( new test_mul_mat_vec_fusion( GGML_TYPE_Q4_K , GGML_GLU_OP_SWIGLU , 2 , rows , 256 , 10813false, 16 , 8 , false, false, true, false, { 1 , 1 })); 10814} 10815 10816for (auto gate : { GATING_FUNC_SOFTMAX , GATING_FUNC_SIGMOID , GATING_FUNC_SOFTMAX_WEIGHT , GATING_FUNC_SQRT_SOFTPLUS }) { 10817for (bool with_norm : {false, true}) { 10818for (bool bias_probs : {false, true}) { 10819for (float scale_w : { 0.0f , 2.0f }) { 10820test_cases . emplace_back ( new test_topk_moe({ 8 , 22 , 1 , 1 }, 4 , with_norm , bias_probs , gate , scale_w )); 10821test_cases . emplace_back ( new test_topk_moe({ 31 , 22 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10822test_cases . emplace_back ( new test_topk_moe({ 32 , 22 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10823test_cases . emplace_back ( new test_topk_moe({ 40 , 22 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10824test_cases . emplace_back ( new test_topk_moe({ 71 , 22 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10825test_cases . emplace_back ( new test_topk_moe({ 128 , 1 , 1 , 1 }, 128 , with_norm , bias_probs , gate , scale_w )); 10826test_cases . emplace_back ( new test_topk_moe({ 129 , 1 , 1 , 1 }, 128 , with_norm , bias_probs , gate , scale_w )); 10827test_cases . emplace_back ( new test_topk_moe({ 160 , 4 , 1 , 1 }, 160 , with_norm , bias_probs , gate , scale_w )); 10828test_cases . emplace_back ( new test_topk_moe({ 256 , 22 , 1 , 1 }, 6 , with_norm , bias_probs , gate , scale_w )); // Used by DeepSeek-V4 10829test_cases . emplace_back ( new test_topk_moe({ 288 , 22 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); // Used by StepFun 3.7 10830// rows at and just past the limit where one block still covers all rows 10831test_cases . emplace_back ( new test_topk_moe({ 32 , 8 , 1 , 1 }, 4 , with_norm , bias_probs , gate , scale_w )); 10832test_cases . emplace_back ( new test_topk_moe({ 32 , 8 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10833test_cases . emplace_back ( new test_topk_moe({ 32 , 9 , 1 , 1 }, 8 , with_norm , bias_probs , gate , scale_w )); 10834} 10835} 10836} 10837} 10838 10839// Cover the supported boundaries, common k = 8 shapes, interleaved views and adds, and k = 16 fallback. 10840test_cases . emplace_back ( new test_moe_weighted_reduction( 63 , 2 , 17 )); 10841test_cases . emplace_back ( new test_moe_weighted_reduction( 2048 , 8 , 128 )); 10842test_cases . emplace_back ( new test_moe_weighted_reduction( 2048 , 8 , 128 , false, true)); 10843test_cases . emplace_back ( new test_moe_weighted_reduction( 63 , 12 , 33 , true, true, true)); 10844test_cases . emplace_back ( new test_moe_weighted_reduction( 2048 , 15 , 40 , false, true)); 10845test_cases . emplace_back ( new test_moe_weighted_reduction( 2048 , 16 , 32 , false, true)); 10846 10847test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 1 , 1 )); 10848test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 16 , 1 , 1 )); 10849test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 16 , 1 , 1 , 1 , true, true)); 10850test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 16 , 1 , 1 , 1 , false, true)); 10851test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 16 , 64 , 1 , 2 )); 10852test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 1 )); 10853test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 )); 10854test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 8 , 32 , 4 , 2 , 2 )); 10855test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 , 1 , true)); 10856test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 1 , 1 , true)); 10857// KDA (vector gate) 10858test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 1 , 1 , 1 , false, true)); 10859test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 1 , 2 , 1 , false, true)); 10860test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 16 , 1 , 2 , 1 , false, true)); 10861test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 32 , 4 , 1 , 1 , false, true)); 10862test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 , 1 , false, true)); 10863test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 8 , 32 , 4 , 2 , 2 , false, true)); 10864test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 , 1 , true, true)); 10865test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 16 , 4 , 2 , 1 , true, true)); 10866// chunked path: multi-chunk and non-multiple-of-chunk-size (chunk_size=64 GDN, 16 KDA) 10867test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 64 , 1 )); 10868test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 127 , 1 )); 10869test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 256 , 1 )); 10870test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 65 , 1 )); 10871test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 100 , 1 )); 10872test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 200 , 1 )); 10873test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 127 , 2 )); 10874test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 64 , 1 , 1 , false, true)); 10875test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 33 , 1 , 1 , false, true)); 10876test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 100 , 1 , 1 , false, true)); 10877 10878// K > 1: output keeps the last min(n_tokens, K) per-token snapshots, ordered most-recent-first 10879// (slot 0 = final state, slot s = state s tokens back). 10880// exact-match cases (K == n_seq_tokens): 10881test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 16 , 2 , 1 , 1 , false, false, /*K=*/ 2 )); 10882test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 32 , 4 , 1 , 1 , false, false, /*K=*/ 4 )); 10883test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 , 1 , false, false, /*K=*/ 4 )); 10884test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 8 , 128 , 4 , 1 , 1 , false, false, /*K=*/ 4 )); 10885test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 4 , 2 , 1 , false, true, /*K=*/ 4 )); 10886test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 8 , 32 , 4 , 2 , 2 , false, true, /*K=*/ 4 )); 10887// overflow: n_tokens > K — only the last K snapshots kept. 10888test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 32 , 8 , 1 , 1 , false, false, /*K=*/ 3 )); 10889test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 64 , 16 , 2 , 1 , false, false, /*K=*/ 4 )); 10890 10891// gdn + cache cpy fusion (K > 1) 10892test_cases . emplace_back ( new test_gated_delta_net_cache_fusion( GGML_TYPE_F32 , 4 , 32 , 2 , 1 , 2 )); 10893test_cases . emplace_back ( new test_gated_delta_net_cache_fusion( GGML_TYPE_F32 , 4 , 64 , 4 , 1 , 2 )); 10894test_cases . emplace_back ( new test_gated_delta_net_cache_fusion( GGML_TYPE_F32 , 4 , 32 , 4 , 1 , 4 )); 10895test_cases . emplace_back ( new test_gated_delta_net_cache_fusion( GGML_TYPE_F32 , 8 , 32 , 4 , 2 , 4 )); 10896test_cases . emplace_back ( new test_gated_delta_net_cache_fusion( GGML_TYPE_F32 , 4 , 32 , 8 , 1 , 4 )); 10897 10898#if 0 10899// these tests are disabled to save execution time, sbut they can be handy for debugging 10900test_cases . emplace_back ( new test_llama( 2 , true)); 10901test_cases . emplace_back ( new test_llama( 1 )); 10902test_cases . emplace_back ( new test_llama( 2 )); 10903test_cases . emplace_back ( new test_falcon( 1 )); 10904test_cases . emplace_back ( new test_falcon( 2 )); 10905#endif 10906 10907// lightning_indexer 10908for (int kv : { 256 }) { 10909for (int bs : { 1 , 512 }) { 10910for (int nh : { 32 , 64 }) { 10911for (auto [ ns , nm ] : { std::pair{ 1 , 1 }, std::pair{ 4 , 4 }, std::pair{ 4 , 1 } }) { 10912for (ggml_type type_K : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_Q8_0 , GGML_TYPE_Q5_1 , GGML_TYPE_Q5_0 , GGML_TYPE_Q4_1 , GGML_TYPE_Q4_0 , GGML_TYPE_IQ4_NL }) { 10913test_cases . emplace_back ( new test_lightning_indexer( 128 , nh , kv , bs , ns , nm , type_K )); 10914} 10915} 10916} 10917} 10918} 10919 10920for (int kv : { 1 , 7 , 8 , 63 , 64 , 65 }) { 10921for (ggml_type type_K : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_Q8_0 , GGML_TYPE_Q5_1 , GGML_TYPE_Q5_0 , GGML_TYPE_Q4_1 , GGML_TYPE_Q4_0 }) { 10922test_cases . emplace_back ( new test_lightning_indexer( 128 , 64 , kv , 32 , 4 , 1 , type_K )); 10923} 10924} 10925 10926return test_cases ; 10927} 10928#ifdef _MSC_VER 10929#pragma optimize("", on) 10930#endif 10931 10932// Test cases for performance evaluation: should be representative of real-world use cases 10933static std::vector < std::unique_ptr < test_case >> make_test_cases_perf () { 10934std::vector < std::unique_ptr < test_case >> test_cases ; 10935 10936// SWIGLU at a 27B-class FFN width, fused [gate|up] vs split operands 10937// note: same bytes either way, so a backend that indexes them differently shows it here 10938for (ggml_type type : { GGML_TYPE_F16 , GGML_TYPE_F32 }) { 10939for (int64_t n_tokens : { 512 , 2048 }) { 10940test_cases . emplace_back ( new test_glu( GGML_GLU_OP_SWIGLU , type , { 2 * 17408 , n_tokens , 1 , 1 }, 0 , false)); 10941test_cases . emplace_back ( new test_glu_split( GGML_GLU_OP_SWIGLU , type , { 17408 , n_tokens , 1 , 1 }, 0 )); 10942} 10943} 10944 10945// CONT of a 0<->2 permute at DeepSeek-V4 lightning-indexer shapes: 10946// indexer_kq is [n_kv, n_tokens, n_head=64] and gets ggml_cont(ggml_permute(.., 2,1,0,3)). 10947for (int64_t n_kv : { 1024 , 1280 , 2048 , 2304 }) { 10948test_cases . emplace_back ( new test_cont( 10949GGML_TYPE_F32 , { n_kv , 64 , 64 , 1 }, false, { 2 , 1 , 0 , 3 })); 10950} 10951for (int64_t n_kv : { 2048 , 2304 }) { 10952test_cases . emplace_back ( new test_cont( 10953GGML_TYPE_F32 , { n_kv , 512 , 64 , 1 }, false, { 2 , 1 , 0 , 3 })); 10954} 10955 10956// LEAKY_RELU at FFN activation width, for direct comparison with RELU 10957for (int64_t n_tokens : { 512 , 2048 }) { 10958test_cases . emplace_back ( new test_leaky_relu( GGML_TYPE_F32 , { 17408 , n_tokens , 1 , 1 }, 0.1f )); 10959} 10960 10961// Conv2d: K=CRS=NPQ=4096 matmul performance 10962uint32_t iwh_idx = 0 ; 10963uint32_t kwh_idx = 1 ; 10964uint32_t Cout_idx = 2 ; 10965uint32_t Cin_idx = 3 ; 10966uint32_t B_idx = 4 ; 10967std::vector < std::array < int, 5 >> cases = { 10968//{IWH, KWH, Cout, Cin, B} 10969// K=CRS=NPQ=4096 conv2d matmul performance 10970{ 19 , 4 , 4096 , 256 , 16 }, 10971// K=128, CRS=128, NPQ=4096 10972{ 19 , 4 , 128 , 8 , 16 }, 10973// K=130, CRS=128, NPQ=4096 10974{ 19 , 4 , 130 , 8 , 16 }, 10975// Edge case: K x CRS is small 10976{ 19 , 2 , 4 , 4 , 16 }, 10977// A ConvNet's first layer 10978{ 224 , 3 , 8 , 3 , 1 }, 10979// A ConvNet's first layer with 2x2 convolution, and 1 channel 10980{ 224 , 2 , 8 , 1 , 1 }, 10981// A ConvNet's first layer with 2x2 convolution, and 1 channel, several images in the batch 10982{ 224 , 2 , 8 , 1 , 8 }, 10983// A middle layer of a ConvNet 10984{ 58 , 3 , 64 , 32 , 1 }, 10985// A middle layer of a ConvNet, several images in the batch 10986{ 58 , 3 , 64 , 32 , 8 }, 10987// A deep layer of a ConvNet, several images in the batch 10988{ 16 , 3 , 512 , 128 , 8 }, 10989// High resolution output (large NPQ) 10990{ 1536 , 3 , 64 , 32 , 1 }, 10991}; 10992 10993for (auto kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 10994for (auto act_case : cases ) { 10995// Direct CONV_2D 10996test_cases . emplace_back ( new test_conv_2d( 10997{ act_case [ iwh_idx ], act_case [ iwh_idx ], act_case [ Cin_idx ], act_case [ B_idx ] }, 10998{ act_case [ kwh_idx ], act_case [ kwh_idx ], act_case [ Cin_idx ], act_case [ Cout_idx ] }, 10999kernel_type , 1 , 1 , 0 , 0 , 1 , 1 , false)); // bool cwhn = false 11000test_cases . emplace_back ( new test_conv_2d( 11001{ act_case [ iwh_idx ], act_case [ iwh_idx ], act_case [ Cin_idx ], act_case [ B_idx ] }, 11002{ act_case [ kwh_idx ], act_case [ kwh_idx ], act_case [ Cin_idx ], act_case [ Cout_idx ] }, 11003kernel_type , 1 , 1 , 0 , 0 , 1 , 1 , true)); // bool cwhn = true 11004} 11005} 11006 11007struct conv3d_perf_case { 11008int N , IC , ID , IH , IW , OC , KD , KH , KW , s0 , s1 , s2 , p0 , p1 , p2 , d0 , d1 , d2 ; 11009}; 11010 11011const std::vector < conv3d_perf_case > conv3d_cases = { 11012{ 1 , 320 , 8 , 38 , 26 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11013{ 1 , 1280 , 8 , 38 , 26 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11014{ 1 , 320 , 8 , 76 , 52 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11015{ 1 , 1280 , 8 , 76 , 52 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11016{ 1 , 320 , 8 , 152 , 104 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11017#if 0 11018// too slow on some devices 11019{ 1 , 1280 , 8 , 152 , 104 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11020{ 1 , 320 , 4 , 304 , 208 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11021{ 1 , 640 , 4 , 304 , 208 , 1280 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, 11022#endif 11023}; 11024 11025for (ggml_type kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 11026for ( const conv3d_perf_case & c : conv3d_cases ) { 11027test_cases . emplace_back ( new test_conv_3d( 11028c . N , c . IC , c . ID , c . IH , c . IW , 11029c . OC , c . KD , c . KH , c . KW , 11030c . s0 , c . s1 , c . s2 , c . p0 , c . p1 , c . p2 , c . d0 , c . d1 , c . d2 , 11031kernel_type )); 11032} 11033} 11034 11035test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 4096 , 1 , 1 , 1 }, { 1 , 1 , 1 , 1 })); 11036test_cases . emplace_back ( new test_bin_bcast( ggml_add , GGML_TYPE_F32 , { 4096 , 1 , 1 , 1 }, { 1 , 512 , 1 , 1 })); 11037 11038test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F16 , { 512 , 3072 , 1 , 1 })); 11039test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 8192 , 512 , 2 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 2 , 1 , 3 })); 11040test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 3072 , 512 , 2 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 2 , 1 , 3 })); 11041test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_Q4_0 , { 8192 , 512 , 2 , 1 })); 11042test_cases . emplace_back ( new test_cpy( GGML_TYPE_Q4_0 , GGML_TYPE_F32 , { 8192 , 512 , 2 , 1 })); 11043 11044test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 768 * 1024 , 256 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 }, { 0 , 0 , 0 , 0 })); 11045test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 768 * 1024 , 256 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 }, { 0 , 0 , 0 , 0 })); 11046test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 768 , 1024 , 256 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 }, { 0 , 0 , 0 , 0 })); 11047test_cases . emplace_back ( new test_cpy( GGML_TYPE_BF16 , GGML_TYPE_BF16 , { 768 , 1024 , 256 , 1 }, { -1 , -1 , -1 , -1 }, { 1 , 0 , 2 , 3 }, { 0 , 0 , 0 , 0 })); 11048 11049test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 768 * 1024 , 256 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 11050test_cases . emplace_back ( new test_cpy( GGML_TYPE_F32 , GGML_TYPE_F32 , { 768 , 1024 , 256 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 11051test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 768 * 1024 , 256 , 1 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 11052test_cases . emplace_back ( new test_cpy( GGML_TYPE_F16 , GGML_TYPE_F16 , { 768 , 1024 , 256 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 11053test_cases . emplace_back ( new test_cpy( GGML_TYPE_BF16 , GGML_TYPE_BF16 , { 768 , 1024 , 256 , 1 }, { -1 , -1 , -1 , -1 }, { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }, true)); 11054 11055test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 4096 , 4096 , 5 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11056test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 12888 , 256 , 5 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11057test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 77 , 4096 , 5 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11058test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 1024 , 1024 , 10 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11059test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 77 , 1024 , 10 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11060test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 256 , 256 , 20 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11061test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 64 , 64 , 20 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11062test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { 77 , 64 , 20 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11063 11064test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 32 , 10 , 1 , 1 })); 11065test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 1024 , 10 , 1 , 1 })); 11066test_cases . emplace_back ( new test_argmax( GGML_TYPE_F32 , { 32000 , 512 , 1 , 1 })); 11067 11068test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 512 , 34 , 2 , 1 })); 11069test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 3000 , 80 , 1 , 1 })); 11070test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 3000 , 80 , 4 , 1 })); 11071test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 3000 , 384 , 1 , 1 })); 11072test_cases . emplace_back ( new test_pad_reflect_1d( GGML_TYPE_F32 , { 3000 , 384 , 4 , 1 })); 11073 11074// SNAKE activation fusion at BigVGAN scale (T=7680 = 24 kHz x 320 ms, C=192) 11075test_cases . emplace_back ( new test_snake_fuse( GGML_TYPE_F32 , { 7680 , 192 , 1 , 1 })); 11076test_cases . emplace_back ( new test_snake_fuse( GGML_TYPE_F16 , { 7680 , 192 , 1 , 1 })); 11077test_cases . emplace_back ( new test_snake_fuse( GGML_TYPE_BF16 , { 7680 , 192 , 1 , 1 })); 11078 11079test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 16416 , 1 , 128 , { 8 , 1 }, { 4 , 1 }, { 0 , 2 , 1 , 3 })); 11080test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_F16 , GGML_TYPE_F32 , 128 , 1 , 16416 , { 8 , 1 }, { 4 , 1 }, { 0 , 1 , 2 , 3 }, 2 * 16416 )); 11081 11082// FWHT tests 11083test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 1 , 128 )); 11084test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 1 , 64 )); 11085test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 256 , 1 , 256 )); 11086test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 32 , 128 )); 11087test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 64 , 2048 , 64 )); 11088test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 128 , 2048 , 128 )); 11089test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 256 , 2048 , 256 )); 11090test_cases . emplace_back ( new test_mul_mat_hadamard( GGML_TYPE_F32 , GGML_TYPE_F32 , 512 , 2048 , 512 )); 11091 11092test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 4 , 4 }, { 32 , 64 , 4 , 4 })); 11093test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 2 }, { 32 , 128 , 4 , 2 })); 11094// qwen3next with CHUNK_SIZE 64 11095test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 64 , 64 , 8 , 32 }, { 64 , 64 , 8 , 32 })); 11096// qwen3next with CHUNK_SIZE 128 11097test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 128 , 128 , 4 , 32 }, { 128 , 128 , 4 , 32 })); 11098test_cases . emplace_back ( new test_solve_tri( GGML_TYPE_F32 , { 256 , 256 , 4 , 2 }, { 128 , 256 , 4 , 2 })); 11099 11100test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_LOWER , GGML_TYPE_F32 , { 256 , 256 , 4 , 4 })); 11101test_cases . emplace_back ( new test_tri( GGML_TRI_TYPE_UPPER_DIAG , GGML_TYPE_F32 , { 1024 , 1024 , 8 , 4 })); 11102 11103test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 128 , 128 , 4 , 4 })); 11104test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 2048 , 16 , 5 , 4 })); 11105test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { 20000 , 10 , 4 , 1 })); 11106 11107for (int bs : { 1 , 2 , 3 , 4 , 5 , 8 , 512 }) { 11108for (ggml_type type_a : all_types ) { 11109for (ggml_type type_b : { GGML_TYPE_F32 }) { 11110test_cases . emplace_back ( new test_mul_mat( type_a , type_b , 4096 , bs , 14336 , { 1 , 1 }, { 1 , 1 })); 11111} 11112} 11113} 11114 11115// Q4_K multi-column mat-vec 11116for (int64_t m : { 4096 , 6144 , 6272 , 14336 }) { 11117for (int bs : { 1 , 2 , 3 , 4 , 8 }) { 11118test_cases . emplace_back ( new test_mul_mat( GGML_TYPE_Q4_K , GGML_TYPE_F32 , m , bs , 4096 , { 1 , 1 }, { 1 , 1 })); 11119} 11120} 11121 11122// qwen3-30b-a3b 11123for (int bs : { 1 , 4 , 8 , 32 , 64 , 128 , 256 , 512 }) { 11124for (ggml_type type_a : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_Q4_0 , GGML_TYPE_Q8_0 , GGML_TYPE_Q4_K , GGML_TYPE_Q6_K , GGML_TYPE_IQ2_XS }) { 11125for (ggml_type type_b : { GGML_TYPE_F32 }) { 11126test_cases . emplace_back ( new test_mul_mat_id( type_a , type_b , 128 , 8 , false, 768 , bs , 2048 )); 11127test_cases . emplace_back ( new test_mul_mat_id_fusion( type_a , type_b , 128 , 8 , false, 768 , bs , 2048 , 1 )); 11128} 11129} 11130} 11131 11132for (int bs : { 1 , 4 , 8 , 32 , 64 , 128 , 256 , 512 }) { 11133for (ggml_type type_a : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_Q4_0 , GGML_TYPE_Q8_0 , GGML_TYPE_Q4_K , GGML_TYPE_Q6_K , GGML_TYPE_IQ2_XS }) { 11134for (ggml_type type_b : { GGML_TYPE_F32 }) { 11135test_cases . emplace_back ( new test_mul_mat_id( type_a , type_b , 32 , 4 , false, 1792 , bs , 2048 )); 11136test_cases . emplace_back ( new test_mul_mat_id_fusion( type_a , type_b , 32 , 4 , false, 1792 , bs , 2048 , 1 )); 11137} 11138} 11139} 11140 11141 11142// gpt-oss-20b 11143for (int bs : { 1 , 4 , 8 , 512 }) { 11144for (ggml_type type_a : { GGML_TYPE_MXFP4 }) { 11145for (ggml_type type_b : { GGML_TYPE_F32 }) { 11146test_cases . emplace_back ( new test_mul_mat_id( type_a , type_b , 32 , 4 , false, 2880 , bs , 2880 )); 11147test_cases . emplace_back ( new test_mul_mat_id_fusion( type_a , type_b , 32 , 4 , false, 2880 , bs , 2880 , 1 )); 11148} 11149} 11150} 11151 11152for (int K : { 3 , 5 }) { 11153for (int IC : { 256 , 2560 }) { 11154for (int IW_IH : { 32 , 64 , 256 }) { 11155if ( IC == 2560 && IW_IH == 256 ) { 11156// too big 11157continue ; 11158} 11159test_cases . emplace_back ( new test_im2col( GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_F32 , { IW_IH , IW_IH , IC , 1 }, { K , K , IC , 1 }, 1 , 1 , 1 , 1 , 1 , 1 , true)); 11160} 11161} 11162} 11163 11164// Qwen3-VL-8B https://github.com/ggml-org/llama.cpp/issues/17012 11165test_cases . emplace_back ( new test_flash_attn_ext( 72 , 72 , 16 , { 1 , 1 }, 5776 , 5776 , false, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11166 11167test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11168test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 4 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11169test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_Q4_0 )); 11170test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q4_0 , GGML_TYPE_Q4_0 )); 11171test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11172test_cases . emplace_back ( new test_flash_attn_ext( 64 , 64 , 8 , { 8 , 1 }, 7680 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11173 11174// sparse decode at long context 11175test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 49152 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 0 )); 11176test_cases . emplace_back ( new test_flash_attn_ext( 512 , 512 , 1 , { 8 , 1 }, 49152 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, false, 2048 )); 11177test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 1 }, 49152 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 0 )); 11178test_cases . emplace_back ( new test_flash_attn_ext( 576 , 512 , 1 , { 16 , 1 }, 49152 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, true, 2048 )); 11179 11180// q8_0 KV cases with long context (decode and prompt) 11181test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 128 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11182test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 512 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11183test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 1024 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11184test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 2048 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11185test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11186test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 10000 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11187test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 20000 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11188test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 10000 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11189test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 20000 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11190test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 10000 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11191test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 20000 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_Q8_0 , GGML_TYPE_Q8_0 )); 11192test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 10000 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11193test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 2 , { 16 , 1 }, 20000 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11194 11195test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 4096 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11196test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 4096 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11197test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 16384 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11198test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 16384 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11199test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 65536 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11200test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 65536 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11201test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 131072 , 1 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11202test_cases . emplace_back ( new test_flash_attn_ext( 256 , 256 , 4 , { 6 , 1 }, 131072 , 512 , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 )); 11203 11204for (int kv : { 4096 , 8192 , 16384 , 32768 , 65536 , }) { 11205for (int hs : { 64 , 128 , 256 , 576 , }) { 11206const int hsv = hs == 576 ? 512 : hs ; 11207const bool v_view = hs == 576 ; 11208for (int nr : { 1 , 4 , 8 , }) { 11209for (int nb : { 1 , 4096 , }) { 11210test_cases . emplace_back ( new test_flash_attn_ext( hs , hsv , 8 , { nr , 1 }, kv , nb , true, false, 0 , 0 , GGML_PREC_F32 , GGML_TYPE_F16 , GGML_TYPE_F16 , { 0 , 1 , 2 , 3 }, true, v_view )); 11211} 11212} 11213} 11214} 11215 11216for (int col : { 8192 , 16384 , 32768 , 65536 , 131072 , 262144 , 524288 }) { 11217for (int rows : { 1 , 4 , 16 }){ 11218test_cases . emplace_back ( new test_soft_max( GGML_TYPE_F32 , { col , rows , 1 , 1 }, false, false, GGML_TYPE_F32 , { 1 , 1 }, 1.0f , 0.0f )); 11219} 11220} 11221 11222test_cases . emplace_back ( new test_conv_2d_dw({ 512 , 512 , 256 , 1 }, { 3 , 3 , 1 , 256 }, GGML_TYPE_F32 , 1 , 1 , 1 , false)); 11223test_cases . emplace_back ( new test_conv_2d_dw({ 512 , 512 , 256 , 1 }, { 3 , 3 , 1 , 256 }, GGML_TYPE_F32 , 1 , 1 , 1 , true)); 11224test_cases . emplace_back ( new test_conv_2d_dw({ 112 , 112 , 32 , 1 }, { 3 , 3 , 1 , 32 }, GGML_TYPE_F32 , 1 , 1 , 1 , false)); 11225test_cases . emplace_back ( new test_conv_2d_dw({ 112 , 112 , 32 , 1 }, { 3 , 3 , 1 , 32 }, GGML_TYPE_F32 , 1 , 1 , 1 , true)); 11226test_cases . emplace_back ( new test_conv_2d_dw({ 56 , 56 , 128 , 1 }, { 5 , 5 , 1 , 128 }, GGML_TYPE_F32 , 2 , 2 , 1 , false)); 11227test_cases . emplace_back ( new test_conv_2d_dw({ 56 , 56 , 128 , 1 }, { 5 , 5 , 1 , 128 }, GGML_TYPE_F32 , 2 , 2 , 1 , true)); 11228 11229for (ggml_type kernel_type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 11230test_cases . emplace_back ( new test_conv_transpose_2d({ 256 , 256 , 256 , 1 }, { 3 , 3 , 16 , 256 }, 1 , kernel_type )); 11231test_cases . emplace_back ( new test_conv_transpose_2d({ 16 , 16 , 16 , 1 }, { 3 , 3 , 8 , 16 }, 1 , kernel_type )); 11232test_cases . emplace_back ( new test_conv_transpose_2d({ 10 , 10 , 9 , 1 }, { 3 , 3 , 1 , 9 }, 2 , kernel_type )); 11233} 11234 11235// Memory bound overlap-add of the GEMM + col2im_1d transposed conv path, real vocoder stage shapes 11236test_cases . emplace_back ( new test_col2im_1d( GGML_TYPE_F32 , 16 , 512 , 2048 , 8 , 0 )); 11237test_cases . emplace_back ( new test_col2im_1d( GGML_TYPE_F32 , 4 , 128 , 65536 , 2 , 0 )); 11238test_cases . emplace_back ( new test_col2im_1d( GGML_TYPE_F16 , 16 , 512 , 2048 , 8 , 0 )); 11239 11240test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , { 256 , 256 , 3 , 1 })); 11241 11242 11243for (int n_token : { 1 , 512 }) { 11244test_cases . emplace_back ( new test_add_id( GGML_TYPE_F32 , GGML_TYPE_F32 , 2880 , 128 , 4 , n_token )); 11245test_cases . emplace_back ( new test_add_id( GGML_TYPE_F32 , GGML_TYPE_F32 , 2880 , 32 , 4 , n_token )); 11246} 11247 11248for (bool fw : {true, false}) { // fw == forward 11249for (ggml_type type : { GGML_TYPE_F32 , GGML_TYPE_F16 }) { 11250for (bool ff : {false, true}) { // freq_factors 11251for (float v : { 0 , 1 }) { 11252test_cases . emplace_back ( new test_rope( type , { 128 , 32 , 512 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // llama 7B 11253test_cases . emplace_back ( new test_rope( type , { 128 , 64 , 512 , 1 }, 128 , GGML_ROPE_TYPE_NORMAL , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // llama 65B 11254test_cases . emplace_back ( new test_rope( type , { 80 , 32 , 512 , 1 }, 20 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // neox (stablelm) 11255test_cases . emplace_back ( new test_rope( type , { 64 , 8 , 512 , 1 }, 64 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // neox (falcon 40B) 11256test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 512 , 1 }, 128 , GGML_ROPE_TYPE_MROPE , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // rope_multi,m-rope (qwen2vl 2B) 11257test_cases . emplace_back ( new test_rope( type , { 128 , 12 , 512 , 1 }, 128 , GGML_ROPE_TYPE_IMROPE , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // rope_multi,imrope (qwen3vl 2B) 11258test_cases . emplace_back ( new test_rope( type , { 80 , 16 , 2 , 1 }, 80 , GGML_ROPE_TYPE_VISION , 512 , 1.0f , 0.0f , 1.0f , ff , v , fw )); // rope_multi,m-rope (qwen2vl ViT) 11259} 11260} 11261} 11262} 11263 11264// Real-model RoPE: F32 forward, packed Q, 512-token prefill. 11265test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 8 , 512 , 1 }, 64 , GGML_ROPE_TYPE_IMROPE , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // qwen3.5 0.8B 11266test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 16 , 512 , 1 }, 64 , GGML_ROPE_TYPE_IMROPE , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // qwen3.5 4B 11267test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 256 , 8 , 512 , 1 }, 256 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , false, 0 , true)); // gemma4 E2B sliding 11268test_cases . emplace_back ( new test_rope( GGML_TYPE_F32 , { 512 , 8 , 512 , 1 }, 128 , GGML_ROPE_TYPE_NEOX , 512 , 1.0f , 0.0f , 1.0f , true, 0 , true)); // gemma4 E4B global 11269 11270std::vector < std::array < int64_t, 4 >> reduce_rows_cases = { 11271{ 8192 , 1 , 1 , 1 }, 11272{ 8192 , 8192 , 1 , 1 }, 11273{ 128 , 8192 , 1 , 1 }, 11274}; 11275 11276for (auto it : reduce_rows_cases ){ 11277test_cases . emplace_back ( new test_mean( GGML_TYPE_F32 , it )); 11278test_cases . emplace_back ( new test_sum_rows( GGML_TYPE_F32 , it )); 11279test_cases . emplace_back ( new test_sum( GGML_TYPE_F32 , it )); 11280} 11281 11282test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 65000 , 16 , 1 , 1 })); 11283test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 200000 , 1 , 1 , 1 })); 11284test_cases . emplace_back ( new test_argsort( GGML_TYPE_F32 , { 200000 , 16 , 1 , 1 })); 11285 11286test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 2 , 1 , 1 , 1 }, 1 )); 11287// widths around the tiling threshold 11288for (auto cols : { 4096 , 8192 , 12288 , 16384 , 24576 , 32768 , 65536 , 131072 }) { 11289for (auto nrows : { 1 , 16 }) { 11290test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { cols , nrows , 1 , 1 }, 16 )); 11291} 11292} 11293for (auto k : { 1 , 4 , 8 , 10 , 16 , 32 , 40 , 400 }) { 11294for (auto nrows : { 1 , 16 }) { 11295for (auto cols : { k , 1000 , 65000 , 200000 }) { 11296test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { cols , nrows , 1 , 1 }, k )); 11297} 11298} 11299} 11300 11301// qwen4exp sparse-attention indexer: nrows = n_tokens/n_stream, so tg gives nrows==1. 11302// Sweep nrows to expose how much of the device a single row leaves idle. 11303for (auto cols : { 8192 , 32768 , 131072 }) { 11304for (auto nrows : { 1 , 2 , 4 , 8 , 16 , 32 }) { 11305test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { cols , nrows , 1 , 1 }, 2048 )); 11306} 11307} 11308// backend sampler: one row of the vocab (llama-sampler.cpp top_k) 11309for (auto k : { 20 , 40 }) { 11310test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { 151936 , 1 , 1 , 1 }, k )); 11311} 11312 11313// short rows, many of them: MoE routing and group selection. The opposite corner from 11314// the indexer, and the one where a work-group per row is the wasteful choice. 11315for (auto cols : { 2 , 16 , 128 , 1024 }) { 11316for (auto nrows : { 1024 , 8192 }) { 11317for (auto k : { 1 , 2 , 8 , 16 , 32 }) { 11318if ( k <= cols ) { 11319test_cases . emplace_back ( new test_top_k( GGML_TYPE_F32 , { cols , nrows , 1 , 1 }, k )); 11320} 11321} 11322} 11323} 11324 11325for (auto nrows : { 1 , 4 , 8 , 16 }) { 11326for (auto cols : { 128 , 1024 , 4096 , 8192 , 16384 , 32768 , 65536 , 131072 , 200000 , 2000000 }) { 11327test_cases . emplace_back ( new test_cumsum( GGML_TYPE_F32 , { cols , nrows , 1 , 1 })); 11328} 11329} 11330 11331// Examples from granite-4.0-h-1b/ggml-model-Q8_0.gguf 11332test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { 515 , 3328 , 1 , 1 }, { 4 , 3328 , 1 , 1 })); // prefill 11333test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { 937 , 8192 , 1 , 1 }, { 4 , 8192 , 1 , 1 })); // prefill 11334test_cases . emplace_back ( new test_ssm_conv( GGML_TYPE_F32 , { 4 , 3328 , 1 , 1 }, { 4 , 3328 , 1 , 1 })); // generate 11335test_cases . emplace_back ( new test_ssm_conv_bias_silu( GGML_TYPE_F32 , { 515 , 3328 , 1 , 1 }, { 4 , 3328 , 1 , 1 }, true)); // prefill 11336test_cases . emplace_back ( new test_ssm_conv_bias_silu( GGML_TYPE_F32 , { 4 , 3328 , 1 , 1 }, { 4 , 3328 , 1 , 1 }, true)); // generate 11337test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 48 , 1 , 512 , 1 )); // prefill 11338test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 64 , 48 , 1 , 1 , 1 )); // generate 11339test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 80 , 128 , 1 , 512 , 1 )); // Nemotron-9B prefill 11340test_cases . emplace_back ( new test_ssm_scan( GGML_TYPE_F32 , 128 , 80 , 128 , 1 , 1 , 1 )); // Nemotron-9B generate 11341 11342// acc 11343test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 1 , 1 }, { 256 , 16 , 1 , 1 }, -1 )); 11344test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 256 , 16 , 2 , 3 }, -1 )); 11345test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 128 , 16 , 2 , 3 }, -1 )); 11346test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 256 , 16 , 2 , 3 }, 1 )); 11347test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 128 , 16 , 2 , 3 }, 2 )); 11348test_cases . emplace_back ( new test_acc( GGML_TYPE_F32 , { 256 , 17 , 2 , 3 }, { 64 , 16 , 2 , 3 }, 3 )); 11349 11350// GATED_DELTA_NET: realistic model configurations 11351// TG: n_seq_tokens=1 (autoregressive) 11352test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 1 , 1 )); // Qwen3.5-like: 32 heads, d=128 11353test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 16 , 64 , 1 , 1 )); // smaller model 11354test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 1 , 1 , 1 , false, true)); // KDA 11355// PP: n_seq_tokens=64,256 (prompt processing) 11356test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 64 , 1 )); // PP-64 11357test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 256 , 1 )); // PP-256 11358test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 512 , 1 )); // PP-512 11359test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 1024 , 1 )); // PP-1024 11360// Small model configs (fewer heads = less GPU occupancy for autoregressive) 11361test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 128 , 64 , 1 )); // 4h PP-64 11362test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 128 , 256 , 1 )); // 4h PP-256 11363test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 128 , 512 , 1 )); // 4h PP-512 11364test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 4 , 128 , 1024 , 1 )); // 4h PP-1024 11365test_cases . emplace_back ( new test_gated_delta_net( GGML_TYPE_F32 , 32 , 128 , 64 , 1 , 1 , false, true)); // KDA PP-64 11366 11367// lightning_indexer 11368for (int kv : { 256 , 4096 , 65536 }) { 11369for (int bs : { 1 , 512 , 2048 }) { 11370for (int nh : { 32 , 64 }) { 11371for (int ns : { 1 , 4 }) { 11372for (ggml_type type_K : { GGML_TYPE_F32 , GGML_TYPE_F16 , GGML_TYPE_BF16 , GGML_TYPE_Q8_0 , GGML_TYPE_Q5_1 , GGML_TYPE_Q5_0 , GGML_TYPE_Q4_1 , GGML_TYPE_Q4_0 , GGML_TYPE_IQ4_NL }) { 11373test_cases . emplace_back ( new test_lightning_indexer( 128 , nh , kv , bs , ns , ns , type_K )); 11374} 11375} 11376} 11377} 11378} 11379 11380// launch-overhead isolation: single L2_NORM launch vs batched siblings at the GDN 11381// production shape (strided qkv views) -- perf-mode only, the eval list has its own 11382// 2/4-wide coverage 11383for (int n : { 128 , 256 }) { 11384test_cases . emplace_back ( new test_l2_norm( GGML_TYPE_F32 , { n , 16 , 16 , 1 }, 1e-12f , false, false)); 11385test_cases . emplace_back ( new test_l2_norm_batch( GGML_TYPE_F32 , { n , 16 , 16 , 1 }, 2 , 1e-12f , true)); 11386test_cases . emplace_back ( new test_l2_norm_batch( GGML_TYPE_F32 , { n , 16 , 16 , 1 }, 4 , 1e-12f , true)); 11387} 11388 11389 11390return test_cases ; 11391} 11392 11393static std::vector < std::unique_ptr < test_case >> make_test_cases_from_file ( const char * path ) { 11394std::ifstream f (path); 11395 11396if (! f . is_open ()) { 11397throw std:: runtime_error ( "Unable to read test file" ); 11398} 11399 11400std::vector < std::unique_ptr < test_case >> test_cases ; 11401 11402std::string line ; 11403 11404while (std:: getline ( f , line )) { 11405std::istringstream iss (line); 11406 11407ggml_op op ; 11408ggml_type type ; 11409std::array < int64_t, 4 > ne ; 11410std::array < int32_t, GGML_MAX_OP_PARAMS / sizeof (int32_t) > op_params = {}; 11411std::string name ; 11412uint64_t tmp ; 11413 11414iss >> tmp ; 11415op = (ggml_op) tmp ; 11416iss >> tmp ; 11417type = (ggml_type) tmp ; 11418 11419for (size_t i = 0 ; i < 4 ; i ++ ) { 11420iss >> ne [ i ]; 11421} 11422 11423iss >> tmp ; 11424for (size_t i = 0 ; i < tmp && i < op_params . size (); i ++ ) { 11425iss >> op_params [ i ]; 11426} 11427 11428iss >> tmp ; 11429 11430size_t num_src = std:: min ((uint64_t) GGML_MAX_SRC , tmp ); 11431std::vector < input_tensor > sources (num_src); 11432for (size_t i = 0 ; i < num_src ; i ++ ) { 11433input_tensor & src = sources [ i ]; 11434iss >> tmp ; 11435src . type = (ggml_type) tmp ; 11436 11437for (size_t i = 0 ; i < 4 ; i ++ ) { 11438iss >> src . ne [ i ]; 11439} 11440for (size_t i = 0 ; i < 4 ; i ++ ) { 11441iss >> src . nb [ i ]; 11442} 11443} 11444 11445iss >> name ; 11446 11447if ( name . length () == 1 && name [ 0 ] == '-' ) { 11448name = "" ; 11449} 11450 11451test_cases . emplace_back ( new test_generic_op( op , type , ne , op_params , sources , std:: move ( name ))); 11452} 11453 11454return test_cases ; 11455} 11456 11457// ---- FA vec (Q,NE): forced-config numerical slice (Metal only) ---- 11458using set_fa_vec_override_t = void ( * )(int, int); 11459using clear_fa_vec_override_t = void ( * )(void); 11460 11461// NL = 32/NE must divide both dk/4 and dv/4. 11462static std::vector < int > fa_vec_legal_ne (int dk , int dv ) { 11463std::vector < int > r ; 11464for (int ne : { 1 , 2 , 4 }) { 11465const int nl = 32 / ne ; 11466if (( dk / 4 ) % nl == 0 && ( dv / 4 ) % nl == 0 ) { 11467r . push_back ( ne ); 11468} 11469} 11470return r ; 11471} 11472 11473static bool op_names_filter_selects ( const char * op_names_filter , const char * op_name ) { 11474if (! op_names_filter ) { 11475return true; 11476} 11477std::string_view filter (op_names_filter); 11478while (! filter . empty ()) { 11479auto comma_pos = filter . find_first_of ( ',' ); 11480const auto lparen_pos = filter . find_first_of ( '(' ); 11481std::string_view entry ; 11482if ( lparen_pos < comma_pos ) { 11483const auto rparen_pos = filter . find_first_of ( ')' ); 11484comma_pos = filter . find_first_of ( ',' , rparen_pos ); 11485entry = filter . substr ( 0 , lparen_pos ); 11486} else { 11487entry = filter . substr ( 0 , comma_pos ); 11488} 11489if ( entry == op_name ) { 11490return true; 11491} 11492filter = comma_pos != std::string_view:: npos ? filter . substr ( comma_pos + 1 ) : "" ; 11493} 11494return false; 11495} 11496 11497// Covers padded rows, sinks, kvpad, multi-SIMDgroup reduction, quantized K/V, and MLA views. 11498// The override is backend-global, so this runs after all parallel workers have joined. 11499static bool run_fa_vec_slice (ggml_backend_t backend , ggml_backend_t backend_cpu , const char * op_names_filter ) { 11500const char * LLAMA_TEST_FA_VEC_DISABLE = getenv ( "LLAMA_TEST_FA_VEC_DISABLE" ); 11501if ( LLAMA_TEST_FA_VEC_DISABLE ) { 11502return true; 11503} 11504 11505if (! op_names_filter_selects ( op_names_filter , "FLASH_ATTN_EXT" )) { 11506return true; 11507} 11508 11509printf ( "Running FA vec slice tests (env LLAMA_TEST_FA_VEC_DISABLE=1 to skip)\n" ); 11510 11511auto * reg = ggml_backend_dev_backend_reg ( ggml_backend_get_device ( backend )); 11512 11513auto set_ov = (set_fa_vec_override_t) ggml_backend_reg_get_proc_address ( reg , "ggml_backend_metal_tuning_set_fa_vec_override" ); 11514auto clear_ov = (clear_fa_vec_override_t) ggml_backend_reg_get_proc_address ( reg , "ggml_backend_metal_tuning_clear_fa_vec_override" ); 11515if (! set_ov || ! clear_ov ) { 11516return true; // not the Metal backend: nothing to force 11517} 11518 11519struct shape_t { int dk , dv ; }; 11520const shape_t shapes [] = { { 128 , 128 }, { 576 , 512 } }; // mainstream head size + MLA shared K/V view 11521const int ne01_pts [] = { 1 , 3 }; // decode, and padded rows for Q=2 and Q=4 11522const int ne11_pts [] = { 512 , 4097 }; // nsg=1, and nsg>=2 together with kvpad 11523const ggml_type types [] = { GGML_TYPE_F16 , GGML_TYPE_Q4_0 }; 11524 11525int n_run = 0 , n_fail = 0 ; 11526for (auto s : shapes ) { 11527for (int ne : fa_vec_legal_ne ( s . dk , s . dv )) { 11528for (int Q : { 1 , 2 , 4 }) { 11529for (ggml_type type_kv : types ) { 11530for (bool sinks : { false, true }) { 11531for (int ne01 : ne01_pts ) { 11532for (int ne11 : ne11_pts ) { 11533set_ov ( Q , ne ); 11534test_flash_attn_ext tc ( s . dk , s . dv , /*nh=*/ 4 , { 1 , 1 }, /*kv=*/ ne11 , /*nb=*/ ne01 , 11535/*mask=*/ true, sinks , 0.0f , 0.0f , GGML_PREC_F32 , 11536type_kv , type_kv ); 11537auto st = tc . eval ( backend , backend_cpu , "FLASH_ATTN_EXT" , nullptr ); 11538clear_ov (); 11539 11540if ( st == test_status_t:: FAIL ) { 11541printf ( " FAIL fa_vec slice: dk=%d dv=%d Q=%d ne=%d type=%s ne01=%d ne11=%d sinks=%d\n" , 11542s . dk , s . dv , Q , ne , ggml_type_name ( type_kv ), ne01 , ne11 , (int) sinks ); 11543n_fail ++ ; 11544} 11545n_run ++ ; 11546} 11547} 11548} 11549} 11550} 11551} 11552} 11553 11554printf ( " fa_vec (Q,NE) slice: %d cases run, %d failed\n" , n_run , n_fail ); 11555 11556return n_fail == 0 ; 11557} 11558 11559static bool test_backend (ggml_backend_t backend , ggml_backend_dev_t dev , test_mode mode , const char * op_names_filter , const char * params_filter , 11560printer * output_printer , const char * test_file_path , int parallel_workers ) { 11561auto filter_test_cases = [](std::vector < std::unique_ptr < test_case >> & test_cases , const char * params_filter ) { 11562if ( params_filter == nullptr ) { 11563return ; 11564} 11565 11566std::regex params_filter_regex (params_filter); 11567 11568for (auto it = test_cases . begin (); it != test_cases . end ();) { 11569if (!std:: regex_search (( * it ) -> vars (), params_filter_regex )) { 11570it = test_cases . erase ( it ); 11571continue ; 11572} 11573 11574it ++ ; 11575} 11576}; 11577 11578std::vector < std::unique_ptr < test_case >> test_cases ; 11579 11580if ( test_file_path == nullptr ) { 11581switch ( mode ) { 11582case MODE_TEST : 11583case MODE_GRAD : 11584case MODE_SUPPORT : 11585test_cases = make_test_cases_eval (); 11586break ; 11587case MODE_PERF : 11588test_cases = make_test_cases_perf (); 11589break ; 11590} 11591} else { 11592test_cases = make_test_cases_from_file ( test_file_path ); 11593} 11594 11595filter_test_cases ( test_cases , params_filter ); 11596 11597if ( mode == MODE_TEST ) { 11598ggml_backend_ptr backend_cpu ( ggml_backend_init_by_type ( GGML_BACKEND_DEVICE_TYPE_CPU , NULL )); 11599if ( backend_cpu == NULL ) { 11600test_operation_info info ( "" , "" , "CPU" ); 11601info . set_error ( "backend" , "Failed to initialize CPU backend" ); 11602output_printer -> print_operation ( info ); 11603return false; 11604} 11605// Use reference implementation on the CPU backend for comparison 11606using ggml_backend_cpu_set_use_ref_t = void ( * )(ggml_backend_t, bool); 11607auto * reg = ggml_backend_dev_backend_reg ( ggml_backend_get_device ( backend_cpu . get ())); 11608auto * set_use_ref = (ggml_backend_cpu_set_use_ref_t) ggml_backend_reg_get_proc_address ( reg , "ggml_backend_cpu_set_use_ref" ); 11609if ( set_use_ref ) { 11610set_use_ref ( backend_cpu . get (), true); 11611} 11612 11613std::atomic < size_t > n_ok = 0 ; 11614std::atomic < size_t > tests_run = 0 ; 11615std::vector < std::string > failed_tests ; 11616std::mutex failed_tests_mutex ; 11617 11618// Each worker grabs a chunk of cases at a time. The chunk shrinks as we 11619// run out of work so that a few slow tests at the tail get spread across 11620// workers instead of landing on one unlucky thread. 11621constexpr size_t MAX_TESTS_PER_ITER = 100 ; 11622std::atomic < size_t > test_idx = 0 ; 11623 11624const auto & next_chunk = [ & ](size_t & my_begin , size_t & my_end ) { 11625const size_t cur = test_idx . load (std:: memory_order_relaxed ); 11626const size_t remaining = cur < test_cases . size () ? test_cases . size () - cur : 0 ; 11627const size_t chunk = std:: max < size_t > ( 1 , std:: min < size_t > ( MAX_TESTS_PER_ITER , remaining / parallel_workers )); 11628my_begin = test_idx . fetch_add ( chunk ); 11629my_end = std:: min ( my_begin + chunk , test_cases . size ()); 11630}; 11631 11632const auto & run_tests = [ & ](ggml_backend_t b , ggml_backend_t b_cpu ) { 11633size_t my_begin , my_end ; 11634next_chunk ( my_begin , my_end ); 11635while ( my_begin < test_cases . size ()) { 11636for (size_t i = my_begin ; i < my_end ; ++ i ) { 11637auto & test = test_cases [ i ]; 11638test_status_t status = test -> eval ( b , b_cpu , op_names_filter , output_printer ); 11639if ( status == test_status_t:: SKIPPED || status == test_status_t:: NOT_SUPPORTED ) { 11640continue ; 11641} 11642tests_run ++ ; 11643if ( status == test_status_t:: OK ) { 11644n_ok ++ ; 11645} else if ( status == test_status_t:: FAIL ) { 11646std::lock_guard < std::mutex > guard (failed_tests_mutex); 11647failed_tests . push_back ( test -> current_op_name + "(" + test -> vars () + ")" ); 11648} 11649} 11650next_chunk ( my_begin , my_end ); 11651} 11652}; 11653 11654if ( parallel_workers <= 1 ) { 11655// Reuse the outer backend / backend_cpu so we don't pay an 11656// extra CPU backend init. 11657run_tests ( backend , backend_cpu . get ()); 11658} else { 11659std::atomic < size_t > workers_started = 0 ; 11660 11661const auto & eval_worker = [ & ]() { 11662ggml_backend_ptr b ( ggml_backend_dev_init ( dev , NULL )); 11663if ( b == NULL ) { 11664return ; 11665} 11666 11667ggml_backend_ptr b_cpu ( ggml_backend_init_by_type ( GGML_BACKEND_DEVICE_TYPE_CPU , NULL )); 11668if ( b_cpu == NULL ) { 11669return ; 11670} 11671 11672if ( set_use_ref ) { 11673set_use_ref ( b_cpu . get (), true); 11674} 11675workers_started ++ ; 11676run_tests ( b . get (), b_cpu . get ()); 11677}; 11678 11679std::vector < std::thread > threads ; 11680threads . reserve ( parallel_workers ); 11681for (int i = 0 ; i < parallel_workers ; ++ i ) { 11682threads . emplace_back ( eval_worker ); 11683} 11684for (auto & t : threads ) { 11685t . join (); 11686} 11687 11688if ( workers_started == 0 && ! test_cases . empty ()) { 11689return false; 11690} 11691} 11692 11693output_printer -> print_summary ( test_summary_info ( n_ok , tests_run , false)); 11694output_printer -> print_failed_tests ( failed_tests ); 11695 11696const bool slice_ok = run_fa_vec_slice ( backend , backend_cpu . get (), op_names_filter ); 11697 11698return n_ok == tests_run && slice_ok ; 11699} 11700 11701if ( mode == MODE_GRAD ) { 11702test_cases . erase ( 11703std:: remove_if ( test_cases . begin (), test_cases . end (), []( const std::unique_ptr < test_case > & tc ) { 11704return tc -> run_whole_graph (); 11705}), 11706test_cases . end () 11707); 11708 11709size_t n_ok = 0 ; 11710for (auto & test : test_cases ) { 11711if ( test -> eval_grad ( backend , op_names_filter , output_printer )) { 11712n_ok ++ ; 11713} 11714} 11715output_printer -> print_summary ( test_summary_info ( n_ok , test_cases . size (), false)); 11716 11717return n_ok == test_cases . size (); 11718} 11719 11720if ( mode == MODE_PERF ) { 11721for (auto & test : test_cases ) { 11722test -> eval_perf ( backend , op_names_filter , output_printer ); 11723} 11724return true; 11725} 11726 11727if ( mode == MODE_SUPPORT ) { 11728// Filter out fusion cases 11729test_cases . erase ( 11730std:: remove_if ( test_cases . begin (), test_cases . end (), []( const std::unique_ptr < test_case > & tc ) { 11731return tc -> run_whole_graph (); 11732}), 11733test_cases . end () 11734); 11735 11736for (auto & test : test_cases ) { 11737test -> eval_support ( backend , op_names_filter , output_printer ); 11738} 11739return true; 11740} 11741 11742GGML_ABORT ( "fatal error" ); 11743} 11744 11745static void list_all_ops () { 11746printf ( "GGML operations:\n" ); 11747std::set < std::string > all_ops ; 11748 11749for (int i = 1 ; i < GGML_OP_COUNT ; i ++ ) { 11750all_ops . insert ( ggml_op_name (( enum ggml_op) i )); 11751} 11752for (int i = 0 ; i < GGML_UNARY_OP_COUNT ; i ++ ) { 11753all_ops . insert ( ggml_unary_op_name (( enum ggml_unary_op) i )); 11754} 11755for (int i = 0 ; i < GGML_GLU_OP_COUNT ; i ++ ) { 11756all_ops . insert ( ggml_glu_op_name (( enum ggml_glu_op) i )); 11757} 11758for ( const auto & op : all_ops ) { 11759printf ( " %s\n" , op . c_str ()); 11760} 11761printf ( "\nTotal: %zu operations\n" , all_ops . size ()); 11762} 11763 11764static void show_test_coverage () { 11765std::set < std::string > all_ops ; 11766for (int i = 1 ; i < GGML_OP_COUNT ; i ++ ) { 11767auto op = ( enum ggml_op) i ; 11768if ( op == GGML_OP_VIEW || 11769op == GGML_OP_RESHAPE || 11770op == GGML_OP_PERMUTE || 11771op == GGML_OP_TRANSPOSE || 11772op == GGML_OP_CONT || 11773op == GGML_OP_GLU || 11774op == GGML_OP_UNARY ) { 11775continue ; 11776} 11777all_ops . insert ( ggml_op_name ( op )); 11778} 11779for (int i = 0 ; i < GGML_UNARY_OP_COUNT ; i ++ ) { 11780all_ops . insert ( ggml_unary_op_name (( enum ggml_unary_op) i )); 11781} 11782for (int i = 0 ; i < GGML_GLU_OP_COUNT ; i ++ ) { 11783all_ops . insert ( ggml_glu_op_name (( enum ggml_glu_op) i )); 11784} 11785auto test_cases = make_test_cases_eval (); 11786// Filter out fusion cases 11787test_cases . erase ( 11788std:: remove_if ( test_cases . begin (), test_cases . end (), []( const std::unique_ptr < test_case > & tc ) { 11789return tc -> run_whole_graph (); 11790}), 11791test_cases . end () 11792); 11793 11794std::set < std::string > tested_ops ; 11795 11796ggml_init_params params = { 11797/* .mem_size = */ ggml_tensor_overhead () * 128 + ggml_graph_overhead (), 11798/* .mem_base = */ NULL , 11799/* .no_alloc = */ true, 11800}; 11801 11802for (auto & test_case : test_cases ) { 11803ggml_context_ptr ctx ( ggml_init ( params )); 11804if ( ctx ) { 11805test_case -> mode = MODE_TEST ; 11806ggml_tensor * out = test_case -> build_graph ( ctx . get ()); 11807if ( out && out -> op != GGML_OP_NONE ) { 11808if ( out -> op == GGML_OP_UNARY ) { 11809tested_ops . insert ( ggml_unary_op_name ( ggml_get_unary_op ( out ))); 11810} else if ( out -> op == GGML_OP_GLU ) { 11811tested_ops . insert ( ggml_glu_op_name ( ggml_get_glu_op ( out ))); 11812} else { 11813tested_ops . insert ( ggml_op_name ( out -> op )); 11814} 11815} 11816} 11817} 11818std::set < std::string > covered_ops ; 11819std::set < std::string > uncovered_ops ; 11820for ( const auto & op : all_ops ) { 11821if ( tested_ops . count ( op ) > 0 ) { 11822covered_ops . insert ( op ); 11823} else { 11824uncovered_ops . insert ( op ); 11825} 11826} 11827 11828printf ( "Operations covered by tests (%zu):\n" , covered_ops . size ()); 11829for ( const auto & op : covered_ops ) { 11830printf ( " ✓ %s\n" , op . c_str ()); 11831} 11832printf ( "\nOperations without tests (%zu):\n" , uncovered_ops . size ()); 11833for ( const auto & op : uncovered_ops ) { 11834printf ( " ✗ %s\n" , op . c_str ()); 11835} 11836 11837printf ( "\nCoverage Summary:\n" ); 11838printf ( " Total operations: %zu\n" , all_ops . size ()); 11839printf ( " Tested operations: %zu\n" , covered_ops . size ()); 11840printf ( " Untested operations: %zu\n" , uncovered_ops . size ()); 11841printf ( " Coverage: %.1f%%\n" , (double) covered_ops . size () / all_ops . size () * 100.0 ); 11842} 11843 11844static void usage (char ** argv ) { 11845printf ( "Usage: %s [mode] [-o <op,..>] [-b <backend>] [-p <params regex>] [--output <console|sql|csv>] [--list-ops]" , argv [ 0 ]); 11846printf ( " [--show-coverage] [--test-file <path>] [-j <n>]\n" ); 11847printf ( " valid modes:\n" ); 11848printf ( " - test (default, compare with CPU backend for correctness)\n" ); 11849printf ( " - grad (compare gradients from backpropagation with method of finite differences)\n" ); 11850printf ( " - perf (performance evaluation)\n" ); 11851printf ( " - support (probe backend operation support)\n" ); 11852printf ( " op names for -o are as given by ggml_op_desc() (e.g. ADD, MUL_MAT, etc),\n" ); 11853printf ( " optionally including the full test case string (e.g. \"ADD(type=f16,ne=[1,1,8,1],nr=[1,1,1,1],nf=1)\")\n" ); 11854printf ( " --output specifies output format (default: console, options: console, sql, csv)\n" ); 11855printf ( " --list-ops lists all available GGML operations\n" ); 11856printf ( " --show-coverage shows test coverage\n" ); 11857printf ( " --test-file reads test operators from a test file generated by test-export-graph-ops\n" ); 11858printf ( " -j <n> runs tests using <n> parallel worker threads (default: 1, test mode only)\n" ); 11859} 11860 11861int main (int argc , char ** argv ) { 11862test_mode mode = MODE_TEST ; 11863output_formats output_format = CONSOLE ; 11864const char * op_names_filter = nullptr ; 11865const char * backend_filter = nullptr ; 11866const char * params_filter = nullptr ; 11867const char * test_file_path = nullptr ; 11868int parallel_workers = 1 ; 11869 11870for (int i = 1 ; i < argc ; i ++ ) { 11871if ( strcmp ( argv [ i ], "test" ) == 0 ) { 11872mode = MODE_TEST ; 11873} else if ( strcmp ( argv [ i ], "perf" ) == 0 ) { 11874mode = MODE_PERF ; 11875} else if ( strcmp ( argv [ i ], "grad" ) == 0 ) { 11876mode = MODE_GRAD ; 11877} else if ( strcmp ( argv [ i ], "support" ) == 0 ) { 11878mode = MODE_SUPPORT ; 11879} else if ( strcmp ( argv [ i ], "-o" ) == 0 ) { 11880if ( i + 1 < argc ) { 11881op_names_filter = argv [ ++ i ]; 11882} else { 11883usage ( argv ); 11884return 1 ; 11885} 11886} else if ( strcmp ( argv [ i ], "-b" ) == 0 ) { 11887if ( i + 1 < argc ) { 11888backend_filter = argv [ ++ i ]; 11889} else { 11890usage ( argv ); 11891return 1 ; 11892} 11893} else if ( strcmp ( argv [ i ], "-p" ) == 0 ) { 11894if ( i + 1 < argc ) { 11895params_filter = argv [ ++ i ]; 11896} else { 11897usage ( argv ); 11898return 1 ; 11899} 11900} else if ( strcmp ( argv [ i ], "--output" ) == 0 ) { 11901if ( i + 1 < argc ) { 11902if (! output_format_from_str ( argv [ ++ i ], output_format )) { 11903usage ( argv ); 11904return 1 ; 11905} 11906} else { 11907usage ( argv ); 11908return 1 ; 11909} 11910} else if ( strcmp ( argv [ i ], "--list-ops" ) == 0 ) { 11911list_all_ops (); 11912return 0 ; 11913} else if ( strcmp ( argv [ i ], "--show-coverage" ) == 0 ) { 11914show_test_coverage (); 11915return 0 ; 11916} else if ( strcmp ( argv [ i ], "--test-file" ) == 0 ) { 11917if ( i + 1 < argc ) { 11918test_file_path = argv [ ++ i ]; 11919} else { 11920usage ( argv ); 11921return 1 ; 11922} 11923} else if ( strcmp ( argv [ i ], "-j" ) == 0 ) { 11924if ( i + 1 < argc ) { 11925parallel_workers = atoi ( argv [ ++ i ]); 11926if ( parallel_workers < 1 ) { 11927usage ( argv ); 11928return 1 ; 11929} 11930} else { 11931usage ( argv ); 11932return 1 ; 11933} 11934} else { 11935usage ( argv ); 11936return 1 ; 11937} 11938} 11939 11940// load and enumerate backends 11941ggml_backend_load_all (); 11942 11943// Create printer for output format 11944std::unique_ptr < printer > output_printer = create_printer ( output_format ); 11945if ( output_printer ) { 11946output_printer -> print_header (); 11947} 11948 11949output_printer -> print_testing_start ( testing_start_info ( ggml_backend_dev_count ())); 11950 11951size_t n_ok = 0 ; 11952 11953for (size_t i = 0 ; i < ggml_backend_dev_count (); i ++ ) { 11954ggml_backend_dev_t dev = ggml_backend_dev_get ( i ); 11955 11956if ( backend_filter != NULL && strcmp ( backend_filter , ggml_backend_dev_name ( dev )) != 0 ) { 11957output_printer -> print_backend_init ( 11958backend_init_info ( i , ggml_backend_dev_count (), ggml_backend_dev_name ( dev ), true, "Skipping" )); 11959n_ok ++ ; 11960continue ; 11961} 11962 11963if ( backend_filter == NULL && ggml_backend_dev_type ( dev ) == GGML_BACKEND_DEVICE_TYPE_CPU && mode != MODE_GRAD ) { 11964output_printer -> print_backend_init ( backend_init_info ( 11965i , ggml_backend_dev_count (), ggml_backend_dev_name ( dev ), true, "Skipping CPU backend" )); 11966n_ok ++ ; 11967continue ; 11968} 11969 11970ggml_backend_ptr backend ( ggml_backend_dev_init ( dev , NULL )); 11971GGML_ASSERT ( backend != NULL ); 11972 11973ggml_backend_reg_t reg = ggml_backend_dev_backend_reg ( dev ); 11974auto ggml_backend_set_n_threads_fn = (ggml_backend_set_n_threads_t) ggml_backend_reg_get_proc_address ( reg , "ggml_backend_set_n_threads" ); 11975if ( ggml_backend_set_n_threads_fn ) { 11976// TODO: better value for n_threads 11977ggml_backend_set_n_threads_fn ( backend . get (), N_THREADS ); 11978} 11979 11980size_t free , total ; // NOLINT 11981ggml_backend_dev_memory ( dev , & free , & total ); 11982output_printer -> print_backend_init ( backend_init_info ( i , ggml_backend_dev_count (), ggml_backend_dev_name ( dev ), 11983false, "" , ggml_backend_dev_description ( dev ), 11984total / 1024 / 1024 , free / 1024 / 1024 , true)); 11985 11986bool ok = test_backend ( backend . get (), dev , mode , op_names_filter , params_filter , output_printer . get (), test_file_path , parallel_workers ); 11987 11988if ( ok ) { 11989n_ok ++ ; 11990} 11991output_printer -> print_backend_status ( 11992backend_status_info ( ggml_backend_name ( backend . get ()), ok ? test_status_t:: OK : test_status_t:: FAIL )); 11993} 11994 11995ggml_quantize_free (); 11996 11997if ( output_printer ) { 11998output_printer -> print_footer (); 11999} 12000 12001output_printer -> print_overall_summary ( 12002overall_summary_info ( n_ok , ggml_backend_dev_count (), n_ok == ggml_backend_dev_count ())); 12003 12004if ( n_ok != ggml_backend_dev_count ()) { 12005return 1 ; 12006} 12007 12008return 0 ; 12009}