char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
d8a8beac2
char/aliceai-t5-moe
1#include "ggml.h" 2#include "ggml-backend.h" 3#include "../ggml/src/ggml-impl.h" 4#include "gguf.h" 5 6#include <algorithm> 7#include <array> 8#include <cmath> 9#include <cstdint> 10#include <cstdio> 11#include <random> 12#include <string> 13#include <vector> 14 15constexpr int offset_has_kv = 1000 ; 16constexpr int offset_has_tensors = 2000 ; 17constexpr int offset_has_data = 3000 ; 18 19enum handcrafted_file_type { 20HANDCRAFTED_HEADER_BAD_MAGIC = 10 , 21HANDCRAFTED_HEADER_BAD_VERSION_0 = 15 , 22HANDCRAFTED_HEADER_BAD_VERSION_1 = 20 , 23HANDCRAFTED_HEADER_BAD_VERSION_FUTURE = 30 , 24HANDCRAFTED_HEADER_BAD_N_TENSORS = 40 , 25HANDCRAFTED_HEADER_BAD_N_KV = 50 , 26HANDCRAFTED_HEADER_EMPTY = 800 , 27 28HANDCRAFTED_KV_BAD_KEY_SIZE = 10 + offset_has_kv , 29HANDCRAFTED_KV_EMPTY_KEY = 15 + offset_has_kv , 30HANDCRAFTED_KV_BAD_TYPE = 20 + offset_has_kv , 31// HANDCRAFTED_KV_BAD_VALUE_SIZE = 30 + offset_has_kv, // removed because it can result in allocations > 1 TB (default sanitizer limit) 32HANDCRAFTED_KV_DUPLICATE_KEY = 40 + offset_has_kv , 33HANDCRAFTED_KV_BAD_ALIGN = 50 + offset_has_kv , 34HANDCRAFTED_KV_WRONG_TYPE_ALIGN = 55 + offset_has_kv , 35HANDCRAFTED_KV_SUCCESS = 800 + offset_has_kv , 36 37HANDCRAFTED_TENSORS_BAD_NAME_SIZE = 10 + offset_has_tensors , 38HANDCRAFTED_TENSORS_BAD_N_DIMS = 20 + offset_has_tensors , 39HANDCRAFTED_TENSORS_BAD_SHAPE = 30 + offset_has_tensors , 40HANDCRAFTED_TENSORS_ZERO_DIM = 35 + offset_has_tensors , 41HANDCRAFTED_TENSORS_NE_TOO_BIG = 40 + offset_has_tensors , 42HANDCRAFTED_TENSORS_NBYTES_TOO_BIG = 45 + offset_has_tensors , 43HANDCRAFTED_TENSORS_BAD_TYPE = 50 + offset_has_tensors , 44HANDCRAFTED_TENSORS_BAD_OFFSET = 60 + offset_has_tensors , 45HANDCRAFTED_TENSORS_DUPLICATE_NAME = 70 + offset_has_tensors , 46HANDCRAFTED_TENSORS_BAD_ALIGN = 75 + offset_has_tensors , 47HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN = 80 + offset_has_tensors , 48HANDCRAFTED_TENSORS_SUCCESS = 800 + offset_has_tensors , 49HANDCRAFTED_TENSORS_CUSTOM_ALIGN = 810 + offset_has_tensors , 50 51HANDCRAFTED_DATA_NOT_ENOUGH_DATA = 10 + offset_has_data , 52HANDCRAFTED_DATA_BAD_ALIGN = 15 + offset_has_data , 53HANDCRAFTED_DATA_INCONSISTENT_ALIGN = 20 + offset_has_data , 54HANDCRAFTED_DATA_MEM_SIZE_OVERFLOW = 30 + offset_has_data , 55HANDCRAFTED_DATA_SUCCESS = 800 + offset_has_data , 56HANDCRAFTED_DATA_CUSTOM_ALIGN = 810 + offset_has_data , 57}; 58 59static std::string handcrafted_file_type_name (const enum handcrafted_file_type hft ) { 60switch (hft ) { 61case HANDCRAFTED_HEADER_BAD_MAGIC :return "HEADER_BAD_MAGIC" ; 62case HANDCRAFTED_HEADER_BAD_VERSION_0 :return "HEADER_BAD_VERSION_0" ; 63case HANDCRAFTED_HEADER_BAD_VERSION_1 :return "HEADER_BAD_VERSION_1" ; 64case HANDCRAFTED_HEADER_BAD_VERSION_FUTURE :return "HEADER_BAD_VERSION_FUTURE" ; 65case HANDCRAFTED_HEADER_BAD_N_KV :return "HEADER_BAD_N_KV" ; 66case HANDCRAFTED_HEADER_BAD_N_TENSORS :return "HEADER_BAD_N_TENSORS" ; 67case HANDCRAFTED_HEADER_EMPTY :return "HEADER_EMPTY" ; 68 69case HANDCRAFTED_KV_BAD_KEY_SIZE :return "KV_BAD_KEY_SIZE" ; 70case HANDCRAFTED_KV_EMPTY_KEY :return "KV_EMPTY_KEY" ; 71case HANDCRAFTED_KV_BAD_TYPE :return "KV_BAD_TYPE" ; 72case HANDCRAFTED_KV_DUPLICATE_KEY :return "KV_DUPLICATE_KEY" ; 73case HANDCRAFTED_KV_BAD_ALIGN :return "KV_BAD_ALIGN" ; 74case HANDCRAFTED_KV_WRONG_TYPE_ALIGN :return "KV_WRONG_TYPE_ALIGN" ; 75case HANDCRAFTED_KV_SUCCESS :return "KV_RANDOM_KV" ; 76 77case HANDCRAFTED_TENSORS_BAD_NAME_SIZE :return "TENSORS_BAD_NAME_SIZE" ; 78case HANDCRAFTED_TENSORS_BAD_N_DIMS :return "TENSORS_BAD_N_DIMS" ; 79case HANDCRAFTED_TENSORS_BAD_SHAPE :return "TENSORS_BAD_SHAPE" ; 80case HANDCRAFTED_TENSORS_ZERO_DIM :return "TENSORS_ZERO_DIM" ; 81case HANDCRAFTED_TENSORS_NE_TOO_BIG :return "TENSORS_NE_TOO_BIG" ; 82case HANDCRAFTED_TENSORS_NBYTES_TOO_BIG :return "TENSORS_NBYTES_TOO_BIG" ; 83case HANDCRAFTED_TENSORS_BAD_TYPE :return "TENSORS_BAD_TYPE" ; 84case HANDCRAFTED_TENSORS_BAD_OFFSET :return "TENSORS_BAD_OFFSET" ; 85case HANDCRAFTED_TENSORS_DUPLICATE_NAME :return "TENSORS_DUPLICATE_NAME" ; 86case HANDCRAFTED_TENSORS_BAD_ALIGN :return "TENSORS_BAD_ALIGN" ; 87case HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN :return "TENSORS_INCONSISTENT_ALIGN" ; 88case HANDCRAFTED_TENSORS_SUCCESS :return "TENSORS_SUCCESS" ; 89case HANDCRAFTED_TENSORS_CUSTOM_ALIGN :return "TENSORS_CUSTOM_ALIGN" ; 90 91case HANDCRAFTED_DATA_NOT_ENOUGH_DATA :return "DATA_NOT_ENOUGH_DATA" ; 92case HANDCRAFTED_DATA_BAD_ALIGN :return "DATA_BAD_ALIGN" ; 93case HANDCRAFTED_DATA_INCONSISTENT_ALIGN :return "DATA_INCONSISTENT_ALIGN" ; 94case HANDCRAFTED_DATA_MEM_SIZE_OVERFLOW :return "DATA_MEM_SIZE_OVERFLOW" ; 95case HANDCRAFTED_DATA_SUCCESS :return "DATA_SUCCESS" ; 96case HANDCRAFTED_DATA_CUSTOM_ALIGN :return "DATA_CUSTOM_ALIGN" ; 97 } 98GGML_ABORT ("fatal error" ); 99} 100 101static bool expect_context_not_null (const enum handcrafted_file_type hft ) { 102if (hft == HANDCRAFTED_TENSORS_ZERO_DIM ) { 103return true; 104 } 105if (hft < offset_has_kv ) { 106return hft >=HANDCRAFTED_HEADER_EMPTY ; 107 } 108if (hft < offset_has_tensors ) { 109return hft >=HANDCRAFTED_KV_SUCCESS ; 110 } 111if (hft < offset_has_data ) { 112return hft >=HANDCRAFTED_TENSORS_SUCCESS ; 113 } 114return hft >=HANDCRAFTED_DATA_SUCCESS ; 115} 116 117typedef std::pair < enum ggml_type , std::array < int64_t ,GGML_MAX_DIMS >> tensor_config_t ; 118 119static std::vector < tensor_config_t > get_tensor_configs (std::mt19937 & rng ) { 120 std::vector < tensor_config_t > tensor_configs ; 121tensor_configs .reserve (100 ); 122 123for (int i = 0 ;i < 100 ;++ i ) { 124const enum ggml_type type = ggml_type (rng () %GGML_TYPE_COUNT ); 125if (ggml_type_size (type )== 0 ) { 126continue ; 127 } 128 129 std::array < int64_t ,GGML_MAX_DIMS > shape = {1 ,1 ,1 ,1 }; 130shape [0 ]= (1 + rng () %10 )* ggml_blck_size (type ); 131const int n_dims = 1 + rng () %GGML_MAX_DIMS ; 132for (int i = 1 ;i < n_dims ;++ i ) { 133shape [i ]= 1 + rng () %10 ; 134 } 135 136tensor_configs .push_back (std::make_pair (type ,shape )); 137 } 138 139return tensor_configs ; 140} 141 142static std::vector < std::pair < enum gguf_type ,enum gguf_type >> get_kv_types (std::mt19937 rng ) { 143 std::vector < std::pair < enum gguf_type ,enum gguf_type >> kv_types ; 144kv_types .reserve (100 ); 145 146for (int i = 0 ;i < 100 ;++ i ) { 147const gguf_type type = gguf_type (rng () %GGUF_TYPE_COUNT ); 148 149if (type == GGUF_TYPE_ARRAY ) { 150const gguf_type type_arr = gguf_type (rng () %GGUF_TYPE_COUNT ); 151if (type_arr == GGUF_TYPE_ARRAY ) { 152continue ; 153 } 154kv_types .push_back (std::make_pair (type ,type_arr )); 155continue ; 156 } 157 158kv_types .push_back (std::make_pair (type ,gguf_type (-1 ))); 159 } 160 std::shuffle (kv_types .begin (),kv_types .end (),rng ); 161 162return kv_types ; 163} 164 165template < typename T > 166static void helper_write (FILE * file ,const T & val ) { 167GGML_ASSERT (fwrite (& val ,1 ,sizeof (val ),file )== sizeof (val )); 168} 169 170static void helper_write (FILE * file ,const void * data ,const size_t nbytes ) { 171GGML_ASSERT (fwrite (data ,1 ,nbytes ,file )== nbytes ); 172} 173 174static std::vector < uint8_t > read_file_to_buffer (FILE * file ) { 175GGML_ASSERT (file != nullptr ); 176GGML_ASSERT (fseek (file ,0 ,SEEK_END )== 0 ); 177 178const long size = ftell (file ); 179GGML_ASSERT (size >=0 ); 180 181rewind (file ); 182 183 std::vector < uint8_t > data (static_cast < size_t > (size )); 184GGML_ASSERT (fread (data .data (),1 ,data .size (),file )== data .size ()); 185 186rewind (file ); 187return data ; 188} 189 190struct callback_reader_data { 191const uint8_t * data ; 192size_t size ; 193}; 194 195static size_t read_buffer_callback (void * userdata ,void * output ,uint64_t offset ,size_t len ) { 196GGML_ASSERT (len > 0 ); 197 198const callback_reader_data & reader = * static_cast < callback_reader_data *> (userdata ); 199 200if (offset > reader .size || len > reader .size - offset ) { 201return 0 ; 202 } 203 204const size_t data_offset = static_cast < size_t > (offset ); 205const size_t nread = std::min (len ,reader .size - data_offset ); 206memcpy (static_cast < uint8_t *> (output ),reader .data + data_offset ,nread ); 207return nread ; 208} 209 210static FILE * get_handcrafted_file (const unsigned int seed ,const enum handcrafted_file_type hft ,const int extra_bytes = 0 ) { 211FILE * file = tmpfile (); 212 213if (!file ) { 214return file ; 215 } 216 217 std::mt19937 rng (seed ); 218uint32_t alignment = GGUF_DEFAULT_ALIGNMENT ; 219 220if (hft == HANDCRAFTED_HEADER_BAD_MAGIC ) { 221const char bad_magic [4 ]= {'F' ,'U' ,'G' ,'G' }; 222helper_write (file ,bad_magic ,sizeof (bad_magic )); 223 }else { 224helper_write (file ,GGUF_MAGIC ,4 ); 225 } 226 227if (hft == HANDCRAFTED_HEADER_BAD_VERSION_0 ) { 228const uint32_t version = 0 ; 229helper_write (file ,version ); 230 }else if (hft == HANDCRAFTED_HEADER_BAD_VERSION_1 ) { 231const uint32_t version = 1 ; 232helper_write (file ,version ); 233 }else if (hft == HANDCRAFTED_HEADER_BAD_VERSION_FUTURE ) { 234const uint32_t version = GGUF_VERSION + 1 ; 235helper_write (file ,version ); 236 }else { 237const uint32_t version = GGUF_VERSION ; 238helper_write (file ,version ); 239 } 240 241 std::vector < tensor_config_t > tensor_configs ; 242if (hft >=offset_has_tensors ) { 243tensor_configs = get_tensor_configs (rng ); 244 } 245 246if (hft == HANDCRAFTED_DATA_MEM_SIZE_OVERFLOW ) { 247tensor_configs .resize (2 ); 248 249tensor_configs [0 ]= {GGML_TYPE_I8 , {0x7FFFFFFFFFFFFFC0 ,1 ,1 ,1 } }; 250tensor_configs [1 ]= {GGML_TYPE_I8 , {0x7FFFFFFFFFFFFFC0 ,1 ,1 ,1 } }; 251 } 252 253if (hft == HANDCRAFTED_HEADER_BAD_N_TENSORS ) { 254const uint64_t n_tensors = -1 ; 255helper_write (file ,n_tensors ); 256 }else { 257const uint64_t n_tensors = tensor_configs .size (); 258helper_write (file ,n_tensors ); 259 } 260 261 std::vector < std::pair < enum gguf_type ,enum gguf_type >> kv_types ; 262if (hft >=offset_has_kv ) { 263kv_types = get_kv_types (rng ); 264 } 265 { 266uint64_t n_kv = kv_types .size (); 267if (hft == HANDCRAFTED_KV_BAD_ALIGN || hft == HANDCRAFTED_KV_WRONG_TYPE_ALIGN || 268hft == HANDCRAFTED_TENSORS_BAD_ALIGN || hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN || 269hft == HANDCRAFTED_DATA_BAD_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN ) { 270 271n_kv += 1 ; 272 }else if (hft == HANDCRAFTED_HEADER_BAD_N_KV ) { 273n_kv = -1 ; 274 } 275helper_write (file ,n_kv ); 276 } 277 278if (hft < offset_has_kv ) { 279while (ftell (file ) %alignment != 0 ) { 280const char pad = 0 ; 281helper_write (file ,pad ); 282 } 283 284for (int i = 0 ;i < extra_bytes ;++ i ) { 285const char tmp = 0 ; 286helper_write (file ,tmp ); 287 } 288rewind (file ); 289return file ; 290 } 291 292for (int i = 0 ;i < int (kv_types .size ());++ i ) { 293const enum gguf_type type = gguf_type (hft == HANDCRAFTED_KV_BAD_TYPE ?GGUF_TYPE_COUNT :kv_types [i ].first ); 294const enum gguf_type type_arr = gguf_type (hft == HANDCRAFTED_KV_BAD_TYPE ?GGUF_TYPE_COUNT :kv_types [i ].second ); 295 296const std::string key = hft == HANDCRAFTED_KV_EMPTY_KEY 297 ?"" 298 :"my_key_" + std::to_string ((hft == HANDCRAFTED_KV_DUPLICATE_KEY ?i /2 :i )); 299 300if (hft == HANDCRAFTED_KV_BAD_KEY_SIZE ) { 301const uint64_t n = -1 ; 302helper_write (file ,n ); 303 }else { 304const uint64_t n = key .length (); 305helper_write (file ,n ); 306 } 307helper_write (file ,key .data (),key .length ()); 308 309 { 310const int32_t type32 = int32_t (type ); 311helper_write (file ,type32 ); 312 } 313 314uint32_t data [16 ]; 315for (int j = 0 ;j < 16 ;++ j ) { 316data [j ]= rng (); 317if (type == GGUF_TYPE_STRING || type_arr == GGUF_TYPE_STRING ) { 318data [j ] |=0x01010101 ;// avoid random null-termination of string 319 } 320 } 321 322if (type == GGUF_TYPE_STRING ) { 323const uint64_t n = rng () %sizeof (data ); 324helper_write (file ,n ); 325helper_write (file ,data ,n ); 326continue ; 327 } 328 329if (type == GGUF_TYPE_ARRAY ) { 330 { 331const int32_t type32 = int32_t (type_arr ); 332helper_write (file ,type32 ); 333 } 334if (type_arr == GGUF_TYPE_STRING ) { 335const uint64_t nstr = rng () % (16 + 1 ); 336helper_write (file ,nstr ); 337for (uint64_t istr = 0 ;istr < nstr ;++ istr ) { 338const uint64_t n = rng () % (sizeof (uint32_t )+ 1 ); 339helper_write (file ,n ); 340helper_write (file ,& data [istr ],n ); 341 } 342continue ; 343 } 344const size_t type_size = gguf_type_size (type_arr ); 345const uint64_t n = (rng () %sizeof (data )) /type_size ; 346helper_write (file ,n ); 347helper_write (file ,& data ,n * type_size ); 348continue ; 349 } 350 351helper_write (file ,data ,hft == HANDCRAFTED_KV_BAD_TYPE ?1 :gguf_type_size (type )); 352 } 353 354if (hft == HANDCRAFTED_KV_BAD_ALIGN || hft == HANDCRAFTED_KV_WRONG_TYPE_ALIGN || 355hft == HANDCRAFTED_TENSORS_BAD_ALIGN || hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN || 356hft == HANDCRAFTED_DATA_BAD_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN ) { 357 358const uint64_t n = strlen (GGUF_KEY_GENERAL_ALIGNMENT ); 359helper_write (file ,n ); 360helper_write (file ,GGUF_KEY_GENERAL_ALIGNMENT ,n ); 361 362// HANDCRAFTED_KV_WRONG_TYPE_ALIGN declares general.alignment with a non-UINT32 type, 363// which the loader must reject cleanly instead of aborting on an assertion 364const int32_t type = hft == HANDCRAFTED_KV_WRONG_TYPE_ALIGN ?int32_t (GGUF_TYPE_INT32 ) :int32_t (GGUF_TYPE_UINT32 ); 365helper_write (file ,type ); 366 367alignment = expect_context_not_null (hft ) ?1 :13 ; 368helper_write (file ,alignment ); 369 } 370 371if (hft < offset_has_tensors ) { 372while (ftell (file ) %alignment != 0 ) { 373const char pad = 0 ; 374helper_write (file ,pad ); 375 } 376 377for (int i = 0 ;i < extra_bytes ;++ i ) { 378const char tmp = 0 ; 379helper_write (file ,tmp ); 380 } 381rewind (file ); 382return file ; 383 } 384 385if (hft == HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN || hft == HANDCRAFTED_DATA_INCONSISTENT_ALIGN ) { 386alignment = 1 ; 387 } 388 389uint64_t offset = 0 ; 390for (int i = 0 ;i < int (tensor_configs .size ());++ i ) { 391const ggml_type type = hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG ?GGML_TYPE_I64 :tensor_configs [i ].first ; 392const std::array < int64_t ,GGML_MAX_DIMS > shape = tensor_configs [i ].second ; 393 394 std::string name = "my_tensor" ; 395if (hft != HANDCRAFTED_TENSORS_DUPLICATE_NAME ) { 396name += "_" + std::to_string (i ); 397 } 398if (hft == HANDCRAFTED_TENSORS_BAD_NAME_SIZE ) { 399name += "_with_a_very_long_name_which_is_longer_than_what_is_allowed_for_ggml_tensors" ; 400GGML_ASSERT (name .length () >=GGML_MAX_NAME ); 401 } 402 { 403const uint64_t n = name .length (); 404helper_write (file ,n ); 405 } 406helper_write (file ,name .data (),name .length ()); 407 408uint32_t n_dims = (hft == HANDCRAFTED_TENSORS_NE_TOO_BIG || hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG ) ?2 :1 ; 409for (int i = GGML_MAX_DIMS - 1 ;i >=1 ;-- i ) { 410if (shape [i ]!= 1 ) { 411n_dims = i + 1 ; 412break ; 413 } 414 } 415if (hft == HANDCRAFTED_TENSORS_ZERO_DIM ) { 416n_dims = 2 ; 417 } 418if (hft == HANDCRAFTED_TENSORS_BAD_N_DIMS ) { 419const uint32_t n_dims_bad = GGML_MAX_DIMS + 1 ; 420helper_write (file ,n_dims_bad ); 421 }else { 422helper_write (file ,n_dims ); 423 } 424 425if (hft == HANDCRAFTED_TENSORS_BAD_SHAPE ) { 426const int64_t bad_dim = -1 ; 427for (uint32_t j = 0 ;j < n_dims ;++ j ) { 428helper_write (file ,bad_dim ); 429 } 430 }else if (hft == HANDCRAFTED_TENSORS_ZERO_DIM ) { 431const int64_t zero_shape [2 ]= {shape [0 ],0 }; 432helper_write (file ,zero_shape ,2 * sizeof (int64_t )); 433 }else if (hft == HANDCRAFTED_TENSORS_NE_TOO_BIG ){ 434const int64_t big_dim = 4 * int64_t (INT32_MAX ); 435for (uint32_t j = 0 ;j < n_dims ;++ j ) { 436helper_write (file ,big_dim ); 437 } 438 }else if (hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG ){ 439const size_t big_ne = SIZE_MAX /ggml_type_size (type ); 440const int64_t big_dim = GGML_PAD (int64_t (1.01f * std::pow (big_ne ,1.0f /n_dims ))+ 1 ,ggml_blck_size (type )); 441for (uint32_t j = 0 ;j < n_dims ;++ j ) { 442helper_write (file ,big_dim ); 443 } 444 }else { 445helper_write (file ,shape .data (),n_dims * sizeof (int64_t )); 446 } 447 448 { 449const int32_t type32 = hft == HANDCRAFTED_TENSORS_BAD_TYPE ?GGML_TYPE_COUNT :int32_t (type ); 450helper_write (file ,type32 ); 451 } 452 453if (hft == HANDCRAFTED_TENSORS_BAD_OFFSET ) { 454const uint64_t bad_offset = -1 ; 455helper_write (file ,bad_offset ); 456 }else { 457helper_write (file ,offset ); 458 } 459 460int64_t ne = shape [0 ]; 461for (uint32_t i = 1 ;i < n_dims ;++ i ) { 462ne *=shape [i ]; 463 } 464if (hft == HANDCRAFTED_TENSORS_ZERO_DIM ) { 465ne = 0 ; 466 } 467 468offset += GGML_PAD (ggml_row_size (type ,ne ), (uint64_t )alignment ); 469 } 470 471while (ftell (file ) %alignment != 0 ) { 472const char pad = 0 ; 473helper_write (file ,pad ); 474 } 475 476if (hft >=offset_has_data ) { 477rng .seed (seed + 1 ); 478uint64_t nbytes = offset ; 479if (hft == HANDCRAFTED_DATA_NOT_ENOUGH_DATA ) { 480nbytes -= 1 ; 481 } 482if (hft == HANDCRAFTED_DATA_MEM_SIZE_OVERFLOW ) { 483nbytes = 32 ; 484 } 485for (uint64_t i = 0 ;i < nbytes ;++ i ) { 486const uint8_t random_byte = i %256 ; 487helper_write (file ,random_byte ); 488 } 489 } 490 491for (int i = 0 ;i < extra_bytes ;++ i ) { 492const char tmp = 0 ; 493helper_write (file ,tmp ); 494 } 495rewind (file ); 496return file ; 497} 498 499static bool handcrafted_check_header (const gguf_context * gguf_ctx ,const unsigned int seed ,const bool has_kv ,const bool has_tensors ,const bool alignment_defined ) { 500if (!gguf_ctx ) { 501return false; 502 } 503 504 std::mt19937 rng (seed ); 505 506 std::vector < tensor_config_t > tensor_configs ; 507if (has_tensors ) { 508tensor_configs = get_tensor_configs (rng ); 509 } 510 std::vector < std::pair < enum gguf_type ,enum gguf_type >> kv_types ; 511if (has_kv ) { 512kv_types = get_kv_types (rng ); 513 } 514 515bool ok = true; 516 517if (gguf_get_version (gguf_ctx )!= GGUF_VERSION ) { 518ok = false; 519 } 520if (gguf_get_n_tensors (gguf_ctx )!= int (tensor_configs .size ())) { 521ok = false; 522 } 523if (gguf_get_n_kv (gguf_ctx )!= int (alignment_defined ?kv_types .size ()+ 1 :kv_types .size ())) { 524ok = false; 525 } 526 527return ok ; 528} 529 530static bool handcrafted_check_kv (const gguf_context * gguf_ctx ,const unsigned int seed ,const bool has_tensors ,const bool alignment_defined ) { 531if (!gguf_ctx ) { 532return false; 533 } 534 535 std::mt19937 rng (seed ); 536 537 std::vector < tensor_config_t > tensor_configs ; 538if (has_tensors ) { 539tensor_configs = get_tensor_configs (rng ); 540 } 541 542 std::vector < std::pair < enum gguf_type ,enum gguf_type >> kv_types = get_kv_types (rng ); 543 544bool ok = true; 545 546for (int i = 0 ;i < int (kv_types .size ());++ i ) { 547const enum gguf_type type = gguf_type (kv_types [i ].first ); 548const enum gguf_type type_arr = gguf_type (kv_types [i ].second ); 549 550const std::string key = "my_key_" + std::to_string (i ); 551 552uint32_t data [16 ]; 553for (int j = 0 ;j < 16 ;++ j ) { 554data [j ]= rng (); 555if (type == GGUF_TYPE_STRING || type_arr == GGUF_TYPE_STRING ) { 556data [j ] |=0x01010101 ;// avoid random null-termination of string 557 } 558 } 559 560const char * data8 = reinterpret_cast < const char *> (data ); 561const int id = gguf_find_key (gguf_ctx ,key .c_str ()); 562 563if (type == GGUF_TYPE_STRING ) { 564const char * str = gguf_get_val_str (gguf_ctx ,id ); 565const uint64_t n = strlen (str ); 566const uint64_t n_expected = rng () %sizeof (data ); 567if (n != n_expected ) { 568ok = false; 569continue ; 570 } 571if (!std::equal (str ,str + n ,data8 )) { 572ok = false; 573 } 574continue ; 575 } 576 577if (type == GGUF_TYPE_ARRAY ) { 578const size_t type_size = gguf_type_size (type_arr ); 579const uint64_t arr_n = gguf_get_arr_n (gguf_ctx ,id ); 580 581if (type_arr == GGUF_TYPE_STRING ) { 582const uint64_t nstr_expected = rng () % (16 + 1 ); 583if (arr_n != nstr_expected ) { 584ok = false; 585continue ; 586 } 587for (uint64_t istr = 0 ;istr < nstr_expected ;++ istr ) { 588const char * str = gguf_get_arr_str (gguf_ctx ,id ,istr ); 589const uint64_t n = strlen (str ); 590const uint64_t n_expected = rng () % (sizeof (uint32_t )+ 1 ); 591 592if (n != n_expected ) { 593ok = false; 594continue ; 595 } 596const char * str_expected = reinterpret_cast < const char *> (& data [istr ]); 597if (strncmp (str ,str_expected ,n )!= 0 ) { 598ok = false; 599continue ; 600 } 601 } 602continue ; 603 } 604 605const uint64_t arr_n_expected = (rng () %sizeof (data )) /type_size ; 606if (arr_n != arr_n_expected ) { 607ok = false; 608continue ; 609 } 610 611const char * data_gguf = reinterpret_cast < const char *> (gguf_get_arr_data (gguf_ctx ,id )); 612 613if (type_arr == GGUF_TYPE_BOOL ) { 614for (size_t arr_i = 0 ;arr_i < arr_n ;++ arr_i ) { 615if (bool (data8 [arr_i ])!= bool (data_gguf [arr_i ])) { 616ok = false; 617 } 618 } 619continue ; 620 } 621 622if (!std::equal (data8 ,data8 + arr_n * type_size ,data_gguf )) { 623ok = false; 624 } 625continue ; 626 } 627 628const char * data_gguf = reinterpret_cast < const char *> (gguf_get_val_data (gguf_ctx ,id )); 629 630if (type == GGUF_TYPE_BOOL ) { 631if (bool (* data8 )!= bool (* data_gguf )) { 632ok = false; 633 } 634continue ; 635 } 636 637if (!std::equal (data8 ,data8 + gguf_type_size (type ),data_gguf )) { 638ok = false; 639 } 640 } 641 642const uint32_t expected_alignment = alignment_defined ?1 :GGUF_DEFAULT_ALIGNMENT ; 643if (gguf_get_alignment (gguf_ctx )!= expected_alignment ) { 644ok = false; 645 } 646 647return ok ; 648} 649 650static bool handcrafted_check_tensors (const gguf_context * gguf_ctx ,const unsigned int seed ) { 651if (!gguf_ctx ) { 652return false; 653 } 654 655 std::mt19937 rng (seed ); 656 657 std::vector < tensor_config_t > tensor_configs = get_tensor_configs (rng ); 658 659// Call get_kv_types to get the same RNG state: 660get_kv_types (rng ); 661 662bool ok = true; 663 664const int id_alignment = gguf_find_key (gguf_ctx ,GGUF_KEY_GENERAL_ALIGNMENT ); 665const uint32_t alignment = id_alignment >=0 ?gguf_get_val_u32 (gguf_ctx ,id_alignment ) :GGUF_DEFAULT_ALIGNMENT ; 666 667uint64_t expected_offset = 0 ; 668for (int i = 0 ;i < int (tensor_configs .size ());++ i ) { 669const ggml_type type = tensor_configs [i ].first ; 670const std::array < int64_t ,GGML_MAX_DIMS > shape = tensor_configs [i ].second ; 671 672const std::string name = "my_tensor_" + std::to_string (i ); 673const int id = gguf_find_tensor (gguf_ctx ,name .c_str ()); 674 675if (id >=0 ) { 676if (std::string (gguf_get_tensor_name (gguf_ctx ,id ))!= name ) { 677ok = false; 678 } 679 680if (gguf_get_tensor_type (gguf_ctx ,id )!= type ) { 681ok = false; 682 } 683 684const int64_t * ne = gguf_get_tensor_ne (gguf_ctx ,id ); 685for (int j = 0 ;j < GGML_MAX_DIMS ;++ j ) { 686if (ne [j ]!= shape [j ]) { 687ok = false; 688 } 689 } 690 }else { 691ok = false; 692continue ; 693 } 694 695const size_t offset = gguf_get_tensor_offset (gguf_ctx ,id ); 696 697if (offset != expected_offset ) { 698ok = false; 699 } 700 701int64_t ne = shape [0 ]; 702for (size_t j = 1 ;j < GGML_MAX_DIMS ;++ j ) { 703ne *=shape [j ]; 704 } 705expected_offset += GGML_PAD (ggml_row_size (type ,ne ),alignment ); 706 } 707 708return ok ; 709} 710 711static bool handcrafted_check_tensor_data (const gguf_context * gguf_ctx ,const unsigned int seed ,FILE * file ) { 712if (!gguf_ctx ) { 713return false; 714 } 715 716 std::mt19937 rng (seed ); 717 718 std::vector < tensor_config_t > tensor_configs = get_tensor_configs (rng ); 719 720bool ok = true; 721 722for (int i = 0 ;i < int (tensor_configs .size ());++ i ) { 723const ggml_type type = tensor_configs [i ].first ; 724const std::array < int64_t ,GGML_MAX_DIMS > shape = tensor_configs [i ].second ; 725 726int64_t ne = shape [0 ]; 727for (size_t j = 1 ;j < GGML_MAX_DIMS ;++ j ) { 728ne *=shape [j ]; 729 } 730const size_t size = ggml_row_size (type ,ne ); 731 732const std::string name = "my_tensor_" + std::to_string (i ); 733const size_t offset = gguf_get_tensor_offset (gguf_ctx ,gguf_find_tensor (gguf_ctx ,name .c_str ())); 734 735 std::vector < uint8_t > data (size ); 736GGML_ASSERT (fseek (file ,gguf_get_data_offset (gguf_ctx )+ offset ,SEEK_SET )== 0 ); 737GGML_ASSERT (fread (data .data (),1 ,data .size (),file )== data .size ()); 738 739for (size_t j = 0 ;j < size ;++ j ) { 740const uint8_t expected_byte = (j + offset ) %256 ; 741if (data [j ]!= expected_byte ) { 742ok = false; 743 } 744 } 745 } 746 747return ok ; 748} 749 750static std::pair < int ,int > test_handcrafted_file (const unsigned int seed ) { 751int npass = 0 ; 752int ntest = 0 ; 753 754const std::vector < handcrafted_file_type > hfts = { 755HANDCRAFTED_HEADER_BAD_MAGIC , 756HANDCRAFTED_HEADER_BAD_VERSION_0 , 757HANDCRAFTED_HEADER_BAD_VERSION_1 , 758HANDCRAFTED_HEADER_BAD_VERSION_FUTURE , 759HANDCRAFTED_HEADER_BAD_N_KV , 760HANDCRAFTED_HEADER_BAD_N_TENSORS , 761HANDCRAFTED_HEADER_EMPTY , 762 763HANDCRAFTED_KV_BAD_KEY_SIZE , 764HANDCRAFTED_KV_EMPTY_KEY , 765HANDCRAFTED_KV_BAD_TYPE , 766HANDCRAFTED_KV_DUPLICATE_KEY , 767HANDCRAFTED_KV_BAD_ALIGN , 768HANDCRAFTED_KV_WRONG_TYPE_ALIGN , 769HANDCRAFTED_KV_SUCCESS , 770 771HANDCRAFTED_TENSORS_BAD_NAME_SIZE , 772HANDCRAFTED_TENSORS_BAD_N_DIMS , 773HANDCRAFTED_TENSORS_BAD_SHAPE , 774HANDCRAFTED_TENSORS_ZERO_DIM , 775HANDCRAFTED_TENSORS_NE_TOO_BIG , 776HANDCRAFTED_TENSORS_NBYTES_TOO_BIG , 777HANDCRAFTED_TENSORS_BAD_TYPE , 778HANDCRAFTED_TENSORS_BAD_OFFSET , 779HANDCRAFTED_TENSORS_DUPLICATE_NAME , 780HANDCRAFTED_TENSORS_BAD_ALIGN , 781HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN , 782HANDCRAFTED_TENSORS_SUCCESS , 783HANDCRAFTED_TENSORS_CUSTOM_ALIGN , 784 785HANDCRAFTED_DATA_NOT_ENOUGH_DATA , 786HANDCRAFTED_DATA_BAD_ALIGN , 787HANDCRAFTED_DATA_INCONSISTENT_ALIGN , 788HANDCRAFTED_DATA_MEM_SIZE_OVERFLOW , 789HANDCRAFTED_DATA_SUCCESS , 790HANDCRAFTED_DATA_CUSTOM_ALIGN , 791 }; 792 793for (enum handcrafted_file_type hft :hfts ) { 794printf ("%s: handcrafted_file_type=%s\n" ,__func__ ,handcrafted_file_type_name (hft ).c_str ()); 795FILE * file = get_handcrafted_file (seed ,hft ); 796 797#ifdef _WIN32 798if (!file ) { 799printf ("failed to create tmpfile(), needs elevated privileges on Windows" ); 800printf ("skipping tests" ); 801continue ; 802 } 803#else 804GGML_ASSERT (file ); 805#endif // _WIN32 806 807struct ggml_context * ctx = nullptr ; 808struct gguf_init_params gguf_params = { 809/*no_alloc =*/ false, 810/*ctx =*/ hft >=offset_has_data ?& ctx :nullptr , 811 }; 812 813struct gguf_context * gguf_ctx = gguf_init_from_file_ptr (file ,gguf_params ); 814 815if (expect_context_not_null (hft )) { 816printf ("%s: - context_not_null: " ,__func__ ); 817 }else { 818printf ("%s: - context_null: " ,__func__ ); 819 } 820if (bool (gguf_ctx )== expect_context_not_null (hft )) { 821printf ("\033[1;32mOK\033[0m\n" ); 822npass ++ ; 823 }else { 824printf ("\033[1;31mFAIL\033[0m\n" ); 825 } 826ntest ++ ; 827 828if (hft >=offset_has_data && !expect_context_not_null (hft )) { 829printf ("%s: - no_dangling_ggml_context_pointer: " ,__func__ ); 830if (ctx ) { 831printf ("\033[1;31mFAIL\033[0m\n" ); 832 }else { 833printf ("\033[1;32mOK\033[0m\n" ); 834npass ++ ; 835 } 836ntest ++ ; 837 } 838 839const bool alignment_defined = hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN ; 840 841if (expect_context_not_null (hft )) { 842printf ("%s: - check_header: " ,__func__ ); 843if (handcrafted_check_header (gguf_ctx ,seed ,hft >=offset_has_kv ,hft >=offset_has_tensors ,alignment_defined )) { 844printf ("\033[1;32mOK\033[0m\n" ); 845npass ++ ; 846 }else { 847printf ("\033[1;31mFAIL\033[0m\n" ); 848 } 849ntest ++ ; 850 } 851 852if (expect_context_not_null (hft )&& hft >=offset_has_kv ) { 853printf ("%s: - check_kv: " ,__func__ ); 854if (handcrafted_check_kv (gguf_ctx ,seed ,hft >=offset_has_tensors ,alignment_defined )) { 855printf ("\033[1;32mOK\033[0m\n" ); 856npass ++ ; 857 }else { 858printf ("\033[1;31mFAIL\033[0m\n" ); 859 } 860ntest ++ ; 861 } 862 863// HANDCRAFTED_TENSORS_ZERO_DIM deliberately mangles the tensor shapes to 0 elements, 864// so only assert that it loads without crashing; skip the exact-geometry comparison. 865if (expect_context_not_null (hft )&& hft >=offset_has_tensors && hft != HANDCRAFTED_TENSORS_ZERO_DIM ) { 866printf ("%s: - check_tensors: " ,__func__ ); 867if (handcrafted_check_tensors (gguf_ctx ,seed )) { 868printf ("\033[1;32mOK\033[0m\n" ); 869npass ++ ; 870 }else { 871printf ("\033[1;31mFAIL\033[0m\n" ); 872 } 873ntest ++ ; 874 } 875 876if (expect_context_not_null (hft )&& hft >=offset_has_data ) { 877printf ("%s: - check_tensor_data: " ,__func__ ); 878if (handcrafted_check_tensor_data (gguf_ctx ,seed ,file )) { 879printf ("\033[1;32mOK\033[0m\n" ); 880npass ++ ; 881 }else { 882printf ("\033[1;31mFAIL\033[0m\n" ); 883 } 884ntest ++ ; 885 } 886 887fclose (file ); 888if (gguf_ctx ) { 889ggml_free (ctx ); 890gguf_free (gguf_ctx ); 891 } 892printf ("\n" ); 893 } 894 895 896return std::make_pair (npass ,ntest ); 897} 898 899struct random_gguf_context_result { 900struct gguf_context * gguf_ctx ; 901struct ggml_context * ctx ; 902ggml_backend_buffer_t buffer ; 903}; 904 905static struct random_gguf_context_result get_random_gguf_context (ggml_backend_t backend ,const unsigned int seed ) { 906 std::mt19937 rng (seed ); 907 908struct gguf_context * gguf_ctx = gguf_init_empty (); 909 910for (int i = 0 ;i < 256 ;++ i ) { 911const std::string key = "my_key_" + std::to_string (rng () %1024 ); 912const enum gguf_type type = gguf_type (rng () %GGUF_TYPE_COUNT ); 913 914switch (type ) { 915case GGUF_TYPE_UINT8 :gguf_set_val_u8 (gguf_ctx ,key .c_str (),rng () % (1 <<7 ));break ; 916case GGUF_TYPE_INT8 :gguf_set_val_i8 (gguf_ctx ,key .c_str (),rng () % (1 <<7 )- (1 <<6 ));break ; 917case GGUF_TYPE_UINT16 :gguf_set_val_u16 (gguf_ctx ,key .c_str (),rng () % (1 <<15 ));break ; 918case GGUF_TYPE_INT16 :gguf_set_val_i16 (gguf_ctx ,key .c_str (),rng () % (1 <<15 )- (1 <<14 ));break ; 919case GGUF_TYPE_UINT32 :gguf_set_val_u32 (gguf_ctx ,key .c_str (),rng ());break ; 920case GGUF_TYPE_INT32 :gguf_set_val_i32 (gguf_ctx ,key .c_str (),rng ()- (1 <<30 ));break ; 921case GGUF_TYPE_FLOAT32 :gguf_set_val_f32 (gguf_ctx ,key .c_str (),rng () %1024 - 512 );break ; 922case GGUF_TYPE_BOOL :gguf_set_val_bool (gguf_ctx ,key .c_str (),rng () %2 == 0 );break ; 923case GGUF_TYPE_STRING :gguf_set_val_str (gguf_ctx ,key .c_str (), std::to_string (rng ()).c_str ());break ; 924case GGUF_TYPE_UINT64 :gguf_set_val_u64 (gguf_ctx ,key .c_str (),rng ());break ; 925case GGUF_TYPE_INT64 :gguf_set_val_i64 (gguf_ctx ,key .c_str (),rng ()- (1 <<30 ));break ; 926case GGUF_TYPE_FLOAT64 :gguf_set_val_f32 (gguf_ctx ,key .c_str (),rng () %1024 - 512 );break ; 927case GGUF_TYPE_ARRAY : { 928const enum gguf_type type_arr = gguf_type (rng () %GGUF_TYPE_COUNT ); 929const uint64_t ne = rng () %1024 ; 930 931switch (type_arr ) { 932case GGUF_TYPE_UINT8 : 933case GGUF_TYPE_INT8 : 934case GGUF_TYPE_UINT16 : 935case GGUF_TYPE_INT16 : 936case GGUF_TYPE_UINT32 : 937case GGUF_TYPE_INT32 : 938case GGUF_TYPE_FLOAT32 : 939case GGUF_TYPE_BOOL : 940case GGUF_TYPE_UINT64 : 941case GGUF_TYPE_INT64 : 942case GGUF_TYPE_FLOAT64 : { 943const size_t nbytes = ne * gguf_type_size (type_arr ); 944 std::vector < uint32_t > random_data ((nbytes + sizeof (uint32_t )- 1 ) /sizeof (uint32_t )); 945for (size_t j = 0 ;j < random_data .size ();++ j ) { 946random_data [j ]= rng (); 947if (type_arr == GGUF_TYPE_BOOL ) { 948random_data [j ] &=0x01010101 ;// the sanitizer complains if booleans are not 0 or 1 949 } 950 } 951gguf_set_arr_data (gguf_ctx ,key .c_str (),type_arr ,random_data .data (),ne ); 952 }break ; 953case GGUF_TYPE_STRING : { 954 std::vector < std::string > data_cpp (ne ); 955 std::vector < const char *> data_c (ne ); 956for (size_t j = 0 ;j < data_cpp .size ();++ j ) { 957data_cpp [j ]= std::to_string (rng ()); 958data_c [j ]= data_cpp [j ].c_str (); 959 } 960gguf_set_arr_str (gguf_ctx ,key .c_str (),data_c .data (),ne ); 961 }break ; 962case GGUF_TYPE_ARRAY : { 963break ;// not supported 964 } 965case GGUF_TYPE_COUNT : 966default : { 967GGML_ABORT ("fatal error" ); 968 } 969 } 970 }break ; 971case GGUF_TYPE_COUNT : 972default : { 973GGML_ABORT ("fatal error" ); 974 } 975 } 976 } 977 978struct ggml_init_params ggml_params = { 979/*.mem_size =*/ 256 * ggml_tensor_overhead (), 980/*.mem_buffer =*/ nullptr , 981/*.no_alloc =*/ true, 982 }; 983struct ggml_context * ctx = ggml_init (ggml_params ); 984 985for (int i = 0 ;i < 256 ;++ i ) { 986const std::string name = "my_tensor_" + std::to_string (i ); 987const enum ggml_type type = ggml_type (rng () %GGML_TYPE_COUNT ); 988const size_t type_size = ggml_type_size (type ); 989 990if (type_size == 0 ) { 991continue ; 992 } 993 994const int n_dims = 1 + rng () %GGML_MAX_DIMS ; 995int64_t ne [GGML_MAX_DIMS ]; 996ne [0 ]= (1 + rng () %10 )* ggml_blck_size (type ); 997for (int j = 1 ;j < n_dims ;++ j ) { 998ne [j ]= 1 + rng () %10 ; 999 } 1000 1001struct ggml_tensor * tensor = ggml_new_tensor (ctx ,type ,n_dims ,ne ); 1002ggml_set_name (tensor ,name .c_str ()); 1003 } 1004 1005ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors (ctx ,backend ); 1006for (struct ggml_tensor * t = ggml_get_first_tensor (ctx );t != nullptr ;t = ggml_get_next_tensor (ctx ,t )) { 1007const size_t nbytes = ggml_nbytes (t ); 1008 std::vector < uint32_t > random_data ((nbytes + sizeof (uint32_t )- 1 ) /sizeof (uint32_t )); 1009for (size_t j = 0 ;j < random_data .size ();++ j ) { 1010random_data [j ]= rng (); 1011 } 1012ggml_backend_tensor_set (t ,random_data .data (),0 ,nbytes ); 1013 1014gguf_add_tensor (gguf_ctx ,t ); 1015 } 1016 1017return {gguf_ctx ,ctx ,buf }; 1018} 1019 1020static bool all_kv_in_other (const gguf_context * ctx ,const gguf_context * other ) { 1021bool ok = true; 1022 1023const int n_kv = gguf_get_n_kv (ctx ); 1024for (int id = 0 ;id < n_kv ;++ id ) { 1025const char * name = gguf_get_key (ctx ,id ); 1026 1027const int idx_other = gguf_find_key (other ,name ); 1028if (idx_other < 0 ) { 1029ok = false; 1030continue ; 1031 } 1032 1033const gguf_type type = gguf_get_kv_type (ctx ,id ); 1034if (type != gguf_get_kv_type (other ,idx_other )) { 1035ok = false; 1036continue ; 1037 } 1038 1039if (type == GGUF_TYPE_ARRAY ) { 1040const size_t arr_n = gguf_get_arr_n (ctx ,id ); 1041if (arr_n != gguf_get_arr_n (other ,idx_other )) { 1042ok = false; 1043continue ; 1044 } 1045 1046const gguf_type type_arr = gguf_get_arr_type (ctx ,id ); 1047if (type_arr != gguf_get_arr_type (other ,idx_other )) { 1048ok = false; 1049continue ; 1050 } 1051 1052if (type_arr == GGUF_TYPE_BOOL ) { 1053const int8_t * data = reinterpret_cast < const int8_t *> (gguf_get_arr_data (ctx ,id )); 1054const int8_t * data_other = reinterpret_cast < const int8_t *> (gguf_get_arr_data (other ,idx_other )); 1055for (size_t arr_i = 0 ;arr_i < arr_n ;++ arr_i ) { 1056if (bool (data [arr_i ])!= bool (data_other [arr_i ])) { 1057ok = false; 1058 } 1059 } 1060continue ; 1061 } 1062 1063if (type_arr == GGUF_TYPE_STRING ) { 1064for (size_t arr_i = 0 ;arr_i < arr_n ;++ arr_i ) { 1065const std::string str = gguf_get_arr_str (ctx ,id ,arr_i ); 1066const std::string str_other = gguf_get_arr_str (other ,idx_other ,arr_i ); 1067if (str != str_other ) { 1068ok = false; 1069 } 1070 } 1071continue ; 1072 } 1073 1074const int8_t * data = reinterpret_cast < const int8_t *> (gguf_get_arr_data (ctx ,id )); 1075const int8_t * data_other = reinterpret_cast < const int8_t *> (gguf_get_arr_data (other ,idx_other )); 1076if (!std::equal (data ,data + arr_n * gguf_type_size (type_arr ),data_other )) { 1077ok = false; 1078 } 1079continue ; 1080 } 1081 1082if (type == GGUF_TYPE_STRING ) { 1083const std::string str = gguf_get_val_str (ctx ,id ); 1084const std::string str_other = gguf_get_val_str (other ,idx_other ); 1085if (str != str_other ) { 1086ok = false; 1087 } 1088continue ; 1089 } 1090 1091const char * data = reinterpret_cast < const char *> (gguf_get_val_data (ctx ,id )); 1092const char * data_other = reinterpret_cast < const char *> (gguf_get_val_data (other ,idx_other )); 1093if (!std::equal (data ,data + gguf_type_size (type ),data_other )) { 1094ok = false; 1095 } 1096 } 1097 1098return ok ; 1099} 1100 1101static bool all_tensors_in_other (const gguf_context * ctx ,const gguf_context * other ) { 1102bool ok = true; 1103 1104const int n_tensors = gguf_get_n_tensors (ctx ); 1105for (int id = 0 ;id < n_tensors ;++ id ) { 1106const std::string name = gguf_get_tensor_name (ctx ,id ); 1107 1108const int idx_other = gguf_find_tensor (other ,name .c_str ()); 1109if (id != idx_other ) { 1110ok = false; 1111if (idx_other < 0 ) { 1112continue ; 1113 } 1114 } 1115 1116const ggml_type type = gguf_get_tensor_type (ctx ,id ); 1117if (type != gguf_get_tensor_type (other ,id )) { 1118ok = false; 1119 } 1120 1121const size_t offset = gguf_get_tensor_offset (ctx ,id ); 1122if (offset != gguf_get_tensor_offset (other ,id )) { 1123ok = false; 1124 } 1125 } 1126 1127return ok ; 1128} 1129 1130static bool same_tensor_data (const struct ggml_context * orig ,const struct ggml_context * read ) { 1131bool ok = true; 1132 1133struct ggml_tensor * t_orig = ggml_get_first_tensor (orig ); 1134struct ggml_tensor * t_read = ggml_get_first_tensor (read ); 1135 1136if (std::string (t_read -> name )!= "GGUF tensor data binary blob" ) { 1137return false; 1138 } 1139t_read = ggml_get_next_tensor (read ,t_read ); 1140 1141while (t_orig ) { 1142if (!t_read ) { 1143ok = false; 1144break ; 1145 } 1146 1147const size_t nbytes = ggml_nbytes (t_orig ); 1148if (ggml_nbytes (t_read )!= nbytes ) { 1149ok = false; 1150break ; 1151 } 1152 std::vector < char > data_orig (nbytes ); 1153ggml_backend_tensor_get (t_orig ,data_orig .data (),0 ,nbytes ); 1154if (!std::equal (data_orig .data (),data_orig .data ()+ nbytes ,reinterpret_cast < const char *> (t_read -> data ))) { 1155ok = false; 1156 } 1157 1158t_orig = ggml_get_next_tensor (orig ,t_orig ); 1159t_read = ggml_get_next_tensor (read ,t_read ); 1160 } 1161if (t_read ) { 1162ok = false; 1163 } 1164 1165return ok ; 1166} 1167 1168enum roundtrip_read_mode { 1169ROUNDTRIP_READ_MODE_FILE , 1170ROUNDTRIP_READ_MODE_BUFFER , 1171ROUNDTRIP_READ_MODE_CALLBACK , 1172}; 1173 1174static const char * roundtrip_read_mode_name (const roundtrip_read_mode mode ) { 1175switch (mode ) { 1176case ROUNDTRIP_READ_MODE_FILE :return "file" ; 1177case ROUNDTRIP_READ_MODE_BUFFER :return "buffer" ; 1178case ROUNDTRIP_READ_MODE_CALLBACK :return "callback" ; 1179 } 1180 1181GGML_ABORT ("fatal error" ); 1182} 1183 1184static std::pair < int ,int > test_roundtrip ( 1185ggml_backend_dev_t dev ,const unsigned int seed ,const bool only_meta , 1186const roundtrip_read_mode read_mode ) { 1187ggml_backend_t backend = ggml_backend_dev_init (dev ,nullptr ); 1188printf ("%s: device=%s, backend=%s, only_meta=%s, read_mode=%s\n" , 1189__func__ ,ggml_backend_dev_description (dev ),ggml_backend_name (backend ), 1190only_meta ?"yes" :"no" ,roundtrip_read_mode_name (read_mode )); 1191 1192int npass = 0 ; 1193int ntest = 0 ; 1194 1195struct gguf_context * gguf_ctx_0 ; 1196struct ggml_context * ctx_0 ; 1197ggml_backend_buffer_t bbuf ; 1198 { 1199struct random_gguf_context_result result = get_random_gguf_context (backend ,seed ); 1200gguf_ctx_0 = result .gguf_ctx ; 1201ctx_0 = result .ctx ; 1202bbuf = result .buffer ; 1203 } 1204 1205FILE * file = tmpfile (); 1206 1207#ifdef _WIN32 1208if (!file ) { 1209printf ("failed to create tmpfile(), needs elevated privileges on Windows" ); 1210printf ("skipping tests" ); 1211return std::make_pair (0 ,0 ); 1212 } 1213#else 1214GGML_ASSERT (file ); 1215#endif // _WIN32 1216 1217gguf_write_to_file_ptr (gguf_ctx_0 ,file ,only_meta ); 1218rewind (file ); 1219 1220struct ggml_context * ctx_1 = nullptr ; 1221struct gguf_init_params gguf_params = { 1222/*no_alloc =*/ false, 1223/*ctx =*/ only_meta ?nullptr :& ctx_1 , 1224 }; 1225struct gguf_context * gguf_ctx_1 = nullptr ; 1226const std::vector < uint8_t > data = read_mode == ROUNDTRIP_READ_MODE_FILE 1227 ? std::vector < uint8_t > () 1228 :read_file_to_buffer (file ); 1229 1230if (read_mode == ROUNDTRIP_READ_MODE_BUFFER ) { 1231gguf_ctx_1 = gguf_init_from_buffer (data .data (),data .size (),gguf_params ); 1232 }else if (read_mode == ROUNDTRIP_READ_MODE_CALLBACK ) { 1233callback_reader_data reader = { 1234/*.data = */ data .data (), 1235/*.size = */ data .size (), 1236 }; 1237gguf_ctx_1 = gguf_init_from_callback (read_buffer_callback ,& reader ,4096 ,4ull <<30 /* 4GB */ ,gguf_params ); 1238 }else { 1239gguf_ctx_1 = gguf_init_from_file_ptr (file ,gguf_params ); 1240 } 1241 1242printf ("%s: same_version: " ,__func__ ); 1243if (gguf_get_version (gguf_ctx_0 )== gguf_get_version (gguf_ctx_1 )) { 1244printf ("\033[1;32mOK\033[0m\n" ); 1245npass ++ ; 1246 }else { 1247printf ("\033[1;31mFAIL\033[0m\n" ); 1248 } 1249ntest ++ ; 1250 1251printf ("%s: same_n_kv: " ,__func__ ); 1252if (gguf_get_n_kv (gguf_ctx_0 )== gguf_get_n_kv (gguf_ctx_1 )) { 1253printf ("\033[1;32mOK\033[0m\n" ); 1254npass ++ ; 1255 }else { 1256printf ("\033[1;31mFAIL\033[0m\n" ); 1257 } 1258ntest ++ ; 1259 1260printf ("%s: same_n_tensors: " ,__func__ ); 1261if (gguf_get_n_tensors (gguf_ctx_0 )== gguf_get_n_tensors (gguf_ctx_1 )) { 1262printf ("\033[1;32mOK\033[0m\n" ); 1263npass ++ ; 1264 }else { 1265printf ("\033[1;31mFAIL\033[0m\n" ); 1266 } 1267ntest ++ ; 1268 1269printf ("%s: all_orig_kv_in_read: " ,__func__ ); 1270if (all_kv_in_other (gguf_ctx_0 ,gguf_ctx_1 )) { 1271printf ("\033[1;32mOK\033[0m\n" ); 1272npass ++ ; 1273 }else { 1274printf ("\033[1;31mFAIL\033[0m\n" ); 1275 } 1276ntest ++ ; 1277 1278printf ("%s: all_read_kv_in_orig: " ,__func__ ); 1279if (all_kv_in_other (gguf_ctx_1 ,gguf_ctx_0 )) { 1280printf ("\033[1;32mOK\033[0m\n" ); 1281npass ++ ; 1282 }else { 1283printf ("\033[1;31mFAIL\033[0m\n" ); 1284 } 1285ntest ++ ; 1286 1287printf ("%s: all_orig_tensors_in_read: " ,__func__ ); 1288if (all_tensors_in_other (gguf_ctx_0 ,gguf_ctx_1 )) { 1289printf ("\033[1;32mOK\033[0m\n" ); 1290npass ++ ; 1291 }else { 1292printf ("\033[1;31mFAIL\033[0m\n" ); 1293 } 1294ntest ++ ; 1295 1296printf ("%s: all_read_tensors_in_orig: " ,__func__ ); 1297if (all_tensors_in_other (gguf_ctx_1 ,gguf_ctx_0 )) { 1298printf ("\033[1;32mOK\033[0m\n" ); 1299npass ++ ; 1300 }else { 1301printf ("\033[1;31mFAIL\033[0m\n" ); 1302 } 1303ntest ++ ; 1304 1305if (!only_meta ) { 1306printf ("%s: same_tensor_data: " ,__func__ ); 1307if (same_tensor_data (ctx_0 ,ctx_1 )) { 1308printf ("\033[1;32mOK\033[0m\n" ); 1309npass ++ ; 1310 }else { 1311printf ("\033[1;31mFAIL\033[0m\n" ); 1312 } 1313ntest ++ ; 1314 } 1315 1316ggml_backend_buffer_free (bbuf ); 1317ggml_free (ctx_0 ); 1318ggml_free (ctx_1 ); 1319gguf_free (gguf_ctx_0 ); 1320gguf_free (gguf_ctx_1 ); 1321ggml_backend_free (backend ); 1322fclose (file ); 1323 1324printf ("\n" ); 1325return std::make_pair (npass ,ntest ); 1326} 1327 1328static std::pair < int ,int > test_gguf_set_kv (ggml_backend_dev_t dev ,const unsigned int seed ) { 1329ggml_backend_t backend = ggml_backend_dev_init (dev ,nullptr ); 1330printf ("%s: device=%s, backend=%s\n" ,__func__ ,ggml_backend_dev_description (dev ),ggml_backend_name (backend )); 1331 1332int npass = 0 ; 1333int ntest = 0 ; 1334 1335struct gguf_context * gguf_ctx_0 ; 1336struct ggml_context * ctx_0 ; 1337ggml_backend_buffer_t bbuf_0 ; 1338 { 1339struct random_gguf_context_result result = get_random_gguf_context (backend ,seed ); 1340gguf_ctx_0 = result .gguf_ctx ; 1341ctx_0 = result .ctx ; 1342bbuf_0 = result .buffer ; 1343 } 1344 1345struct gguf_context * gguf_ctx_1 ; 1346struct ggml_context * ctx_1 ; 1347ggml_backend_buffer_t bbuf_1 ; 1348 { 1349struct random_gguf_context_result result = get_random_gguf_context (backend ,seed + 1 ); 1350gguf_ctx_1 = result .gguf_ctx ; 1351ctx_1 = result .ctx ; 1352bbuf_1 = result .buffer ; 1353 } 1354 1355struct gguf_context * gguf_ctx_2 = gguf_init_empty (); 1356 1357gguf_set_kv (gguf_ctx_1 ,gguf_ctx_0 ); 1358gguf_set_kv (gguf_ctx_2 ,gguf_ctx_0 ); 1359 1360printf ("%s: same_n_kv: " ,__func__ ); 1361if (gguf_get_n_kv (gguf_ctx_0 )== gguf_get_n_kv (gguf_ctx_2 )) { 1362printf ("\033[1;32mOK\033[0m\n" ); 1363npass ++ ; 1364 }else { 1365printf ("\033[1;31mFAIL\033[0m\n" ); 1366 } 1367ntest ++ ; 1368 1369printf ("%s: all_kv_0_in_1: " ,__func__ ); 1370if (all_kv_in_other (gguf_ctx_0 ,gguf_ctx_1 )) { 1371printf ("\033[1;32mOK\033[0m\n" ); 1372npass ++ ; 1373 }else { 1374printf ("\033[1;31mFAIL\033[0m\n" ); 1375 } 1376ntest ++ ; 1377 1378printf ("%s: all_kv_0_in_2: " ,__func__ ); 1379if (all_kv_in_other (gguf_ctx_0 ,gguf_ctx_2 )) { 1380printf ("\033[1;32mOK\033[0m\n" ); 1381npass ++ ; 1382 }else { 1383printf ("\033[1;31mFAIL\033[0m\n" ); 1384 } 1385ntest ++ ; 1386 1387gguf_set_kv (gguf_ctx_0 ,gguf_ctx_1 ); 1388 1389printf ("%s: same_n_kv_after_double_copy: " ,__func__ ); 1390if (gguf_get_n_kv (gguf_ctx_0 )== gguf_get_n_kv (gguf_ctx_1 )) { 1391printf ("\033[1;32mOK\033[0m\n" ); 1392npass ++ ; 1393 }else { 1394printf ("\033[1;31mFAIL\033[0m\n" ); 1395 } 1396ntest ++ ; 1397 1398printf ("%s: all_kv_1_in_0_after_double_copy: " ,__func__ ); 1399if (all_kv_in_other (gguf_ctx_1 ,gguf_ctx_0 )) { 1400printf ("\033[1;32mOK\033[0m\n" ); 1401npass ++ ; 1402 }else { 1403printf ("\033[1;31mFAIL\033[0m\n" ); 1404 } 1405ntest ++ ; 1406 1407ggml_backend_buffer_free (bbuf_0 ); 1408ggml_backend_buffer_free (bbuf_1 ); 1409ggml_free (ctx_0 ); 1410ggml_free (ctx_1 ); 1411gguf_free (gguf_ctx_0 ); 1412gguf_free (gguf_ctx_1 ); 1413gguf_free (gguf_ctx_2 ); 1414ggml_backend_free (backend ); 1415 1416printf ("\n" ); 1417return std::make_pair (npass ,ntest ); 1418} 1419 1420static void print_usage () { 1421printf ("usage: test-gguf [seed]\n" ); 1422printf (" if no seed is unspecified then a random seed is used\n" ); 1423} 1424 1425int main (int argc ,char ** argv ) { 1426if (argc > 2 ) { 1427print_usage (); 1428return 1 ; 1429 } 1430 1431 std::random_device rd ; 1432const unsigned int seed = argc < 2 ?rd () : std::stoi (argv [1 ]); 1433 1434// Initialize ggml backends early so the prints aren't interleaved with the test results: 1435ggml_backend_dev_count (); 1436fprintf (stderr ,"\n" ); 1437 1438int npass = 0 ; 1439int ntest = 0 ; 1440 { 1441 std::pair < int ,int > result = test_handcrafted_file (seed ); 1442npass += result .first ; 1443ntest += result .second ; 1444 } 1445 1446for (size_t i = 0 ;i < ggml_backend_dev_count ();++ i ) { 1447ggml_backend_dev_t dev = ggml_backend_dev_get (i ); 1448 1449for (bool only_meta : {true, false}) { 1450 std::pair < int ,int > result = test_roundtrip (dev ,seed ,only_meta ,ROUNDTRIP_READ_MODE_FILE ); 1451npass += result .first ; 1452ntest += result .second ; 1453 } 1454 { 1455 std::pair < int ,int > result = test_roundtrip (dev ,seed ,/*only_meta=*/ false,ROUNDTRIP_READ_MODE_BUFFER ); 1456npass += result .first ; 1457ntest += result .second ; 1458 } 1459 { 1460 std::pair < int ,int > result = test_roundtrip (dev ,seed ,/*only_meta=*/ false,ROUNDTRIP_READ_MODE_CALLBACK ); 1461npass += result .first ; 1462ntest += result .second ; 1463 } 1464 1465 { 1466 std::pair < int ,int > result = test_gguf_set_kv (dev ,seed ); 1467npass += result .first ; 1468ntest += result .second ; 1469 } 1470 } 1471 1472printf ("%d/%d tests passed\n" ,npass ,ntest ); 1473if (npass != ntest ) { 1474printf ("\033[1;31mFAIL\033[0m\n" ); 1475return 1 ; 1476 } 1477printf ("\033[1;32mOK\033[0m\n" ); 1478return 0 ; 1479}