test-gguf.cpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. #include "ggml.h"
  2. #include "ggml-backend.h"
  3. #include "../ggml/src/ggml-impl.h"
  4. #include "gguf.h"
  5. #include <algorithm>
  6. #include <array>
  7. #include <cmath>
  8. #include <cstdint>
  9. #include <cstdio>
  10. #include <random>
  11. #include <string>
  12. #include <vector>
  13. constexpr int offset_has_kv = 1000;
  14. constexpr int offset_has_tensors = 2000;
  15. constexpr int offset_has_data = 3000;
  16. enum handcrafted_file_type {
  17. HANDCRAFTED_HEADER_BAD_MAGIC = 10,
  18. HANDCRAFTED_HEADER_BAD_VERSION_0 = 15,
  19. HANDCRAFTED_HEADER_BAD_VERSION_1 = 20,
  20. HANDCRAFTED_HEADER_BAD_VERSION_FUTURE = 30,
  21. HANDCRAFTED_HEADER_BAD_N_TENSORS = 40,
  22. HANDCRAFTED_HEADER_BAD_N_KV = 50,
  23. HANDCRAFTED_HEADER_EMPTY = 800,
  24. HANDCRAFTED_KV_BAD_KEY_SIZE = 10 + offset_has_kv,
  25. HANDCRAFTED_KV_BAD_TYPE = 20 + offset_has_kv,
  26. // HANDCRAFTED_KV_BAD_VALUE_SIZE = 30 + offset_has_kv, // removed because it can result in allocations > 1 TB (default sanitizer limit)
  27. HANDCRAFTED_KV_DUPLICATE_KEY = 40 + offset_has_kv,
  28. HANDCRAFTED_KV_BAD_ALIGN = 50 + offset_has_kv,
  29. HANDCRAFTED_KV_SUCCESS = 800 + offset_has_kv,
  30. HANDCRAFTED_TENSORS_BAD_NAME_SIZE = 10 + offset_has_tensors,
  31. HANDCRAFTED_TENSORS_BAD_N_DIMS = 20 + offset_has_tensors,
  32. HANDCRAFTED_TENSORS_BAD_SHAPE = 30 + offset_has_tensors,
  33. HANDCRAFTED_TENSORS_NE_TOO_BIG = 40 + offset_has_tensors,
  34. HANDCRAFTED_TENSORS_NBYTES_TOO_BIG = 45 + offset_has_tensors,
  35. HANDCRAFTED_TENSORS_BAD_TYPE = 50 + offset_has_tensors,
  36. HANDCRAFTED_TENSORS_BAD_OFFSET = 60 + offset_has_tensors,
  37. HANDCRAFTED_TENSORS_DUPLICATE_NAME = 70 + offset_has_tensors,
  38. HANDCRAFTED_TENSORS_BAD_ALIGN = 75 + offset_has_tensors,
  39. HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN = 80 + offset_has_tensors,
  40. HANDCRAFTED_TENSORS_SUCCESS = 800 + offset_has_tensors,
  41. HANDCRAFTED_TENSORS_CUSTOM_ALIGN = 810 + offset_has_tensors,
  42. HANDCRAFTED_DATA_NOT_ENOUGH_DATA = 10 + offset_has_data,
  43. HANDCRAFTED_DATA_BAD_ALIGN = 15 + offset_has_data,
  44. HANDCRAFTED_DATA_INCONSISTENT_ALIGN = 20 + offset_has_data,
  45. HANDCRAFTED_DATA_SUCCESS = 800 + offset_has_data,
  46. HANDCRAFTED_DATA_CUSTOM_ALIGN = 810 + offset_has_data,
  47. };
  48. static std::string handcrafted_file_type_name(const enum handcrafted_file_type hft) {
  49. switch (hft) {
  50. case HANDCRAFTED_HEADER_BAD_MAGIC: return "HEADER_BAD_MAGIC";
  51. case HANDCRAFTED_HEADER_BAD_VERSION_0: return "HEADER_BAD_VERSION_0";
  52. case HANDCRAFTED_HEADER_BAD_VERSION_1: return "HEADER_BAD_VERSION_1";
  53. case HANDCRAFTED_HEADER_BAD_VERSION_FUTURE: return "HEADER_BAD_VERSION_FUTURE";
  54. case HANDCRAFTED_HEADER_BAD_N_KV: return "HEADER_BAD_N_KV";
  55. case HANDCRAFTED_HEADER_BAD_N_TENSORS: return "HEADER_BAD_N_TENSORS";
  56. case HANDCRAFTED_HEADER_EMPTY: return "HEADER_EMPTY";
  57. case HANDCRAFTED_KV_BAD_KEY_SIZE: return "KV_BAD_KEY_SIZE";
  58. case HANDCRAFTED_KV_BAD_TYPE: return "KV_BAD_TYPE";
  59. case HANDCRAFTED_KV_DUPLICATE_KEY: return "KV_DUPLICATE_KEY";
  60. case HANDCRAFTED_KV_BAD_ALIGN: return "KV_BAD_ALIGN";
  61. case HANDCRAFTED_KV_SUCCESS: return "KV_RANDOM_KV";
  62. case HANDCRAFTED_TENSORS_BAD_NAME_SIZE: return "TENSORS_BAD_NAME_SIZE";
  63. case HANDCRAFTED_TENSORS_BAD_N_DIMS: return "TENSORS_BAD_N_DIMS";
  64. case HANDCRAFTED_TENSORS_BAD_SHAPE: return "TENSORS_BAD_SHAPE";
  65. case HANDCRAFTED_TENSORS_NE_TOO_BIG: return "TENSORS_NE_TOO_BIG";
  66. case HANDCRAFTED_TENSORS_NBYTES_TOO_BIG: return "TENSORS_NBYTES_TOO_BIG";
  67. case HANDCRAFTED_TENSORS_BAD_TYPE: return "TENSORS_BAD_TYPE";
  68. case HANDCRAFTED_TENSORS_BAD_OFFSET: return "TENSORS_BAD_OFFSET";
  69. case HANDCRAFTED_TENSORS_DUPLICATE_NAME: return "TENSORS_DUPLICATE_NAME";
  70. case HANDCRAFTED_TENSORS_BAD_ALIGN: return "TENSORS_BAD_ALIGN";
  71. case HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN: return "TENSORS_INCONSISTENT_ALIGN";
  72. case HANDCRAFTED_TENSORS_SUCCESS: return "TENSORS_SUCCESS";
  73. case HANDCRAFTED_TENSORS_CUSTOM_ALIGN: return "TENSORS_CUSTOM_ALIGN";
  74. case HANDCRAFTED_DATA_NOT_ENOUGH_DATA: return "DATA_NOT_ENOUGH_DATA";
  75. case HANDCRAFTED_DATA_BAD_ALIGN: return "DATA_BAD_ALIGN";
  76. case HANDCRAFTED_DATA_INCONSISTENT_ALIGN: return "DATA_INCONSISTENT_ALIGN";
  77. case HANDCRAFTED_DATA_SUCCESS: return "DATA_SUCCESS";
  78. case HANDCRAFTED_DATA_CUSTOM_ALIGN: return "DATA_CUSTOM_ALIGN";
  79. }
  80. GGML_ABORT("fatal error");
  81. }
  82. static bool expect_context_not_null(const enum handcrafted_file_type hft) {
  83. if (hft < offset_has_kv) {
  84. return hft >= HANDCRAFTED_HEADER_EMPTY;
  85. }
  86. if (hft < offset_has_tensors) {
  87. return hft >= HANDCRAFTED_KV_SUCCESS;
  88. }
  89. if (hft < offset_has_data) {
  90. return hft >= HANDCRAFTED_TENSORS_SUCCESS;
  91. }
  92. return hft >= HANDCRAFTED_DATA_SUCCESS;
  93. }
  94. typedef std::pair<enum ggml_type, std::array<int64_t, GGML_MAX_DIMS>> tensor_config_t;
  95. static std::vector<tensor_config_t> get_tensor_configs(std::mt19937 & rng) {
  96. std::vector<tensor_config_t> tensor_configs;
  97. tensor_configs.reserve(100);
  98. for (int i = 0; i < 100; ++i) {
  99. const enum ggml_type type = ggml_type(rng() % GGML_TYPE_COUNT);
  100. if (ggml_type_size(type) == 0) {
  101. continue;
  102. }
  103. std::array<int64_t, GGML_MAX_DIMS> shape = {1, 1, 1, 1};
  104. shape[0] = (1 + rng() % 10) * ggml_blck_size(type);
  105. const int n_dims = 1 + rng() % GGML_MAX_DIMS;
  106. for (int i = 1; i < n_dims; ++i) {
  107. shape[i] = 1 + rng() % 10;
  108. }
  109. tensor_configs.push_back(std::make_pair(type, shape));
  110. }
  111. return tensor_configs;
  112. }
  113. static std::vector<std::pair<enum gguf_type, enum gguf_type>> get_kv_types(std::mt19937 rng) {
  114. std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
  115. kv_types.reserve(100);
  116. for (int i = 0; i < 100; ++i) {
  117. const gguf_type type = gguf_type(rng() % GGUF_TYPE_COUNT);
  118. if (type == GGUF_TYPE_ARRAY) {
  119. const gguf_type type_arr = gguf_type(rng() % GGUF_TYPE_COUNT);
  120. if (type_arr == GGUF_TYPE_ARRAY) {
  121. continue;
  122. }
  123. kv_types.push_back(std::make_pair(type, type_arr));
  124. continue;
  125. }
  126. kv_types.push_back(std::make_pair(type, gguf_type(-1)));
  127. }
  128. std::shuffle(kv_types.begin(), kv_types.end(), rng);
  129. return kv_types;
  130. }
  131. template <typename T>
  132. static void helper_write(FILE * file, const T & val) {
  133. GGML_ASSERT(fwrite(&val, 1, sizeof(val), file) == sizeof(val));
  134. }
  135. static void helper_write(FILE * file, const void * data, const size_t nbytes) {
  136. GGML_ASSERT(fwrite(data, 1, nbytes, file) == nbytes);
  137. }
  138. static FILE * get_handcrafted_file(const unsigned int seed, const enum handcrafted_file_type hft, const int extra_bytes = 0) {
  139. FILE * file = tmpfile();
  140. if (!file) {
  141. return file;
  142. }
  143. std::mt19937 rng(seed);
  144. uint32_t alignment = GGUF_DEFAULT_ALIGNMENT;
  145. if (hft == HANDCRAFTED_HEADER_BAD_MAGIC) {
  146. const char bad_magic[4] = {'F', 'U', 'G', 'G'};
  147. helper_write(file, bad_magic, sizeof(bad_magic));
  148. } else {
  149. helper_write(file, GGUF_MAGIC, 4);
  150. }
  151. if (hft == HANDCRAFTED_HEADER_BAD_VERSION_0) {
  152. const uint32_t version = 0;
  153. helper_write(file, version);
  154. } else if (hft == HANDCRAFTED_HEADER_BAD_VERSION_1) {
  155. const uint32_t version = 1;
  156. helper_write(file, version);
  157. } else if (hft == HANDCRAFTED_HEADER_BAD_VERSION_FUTURE) {
  158. const uint32_t version = GGUF_VERSION + 1;
  159. helper_write(file, version);
  160. } else {
  161. const uint32_t version = GGUF_VERSION;
  162. helper_write(file, version);
  163. }
  164. std::vector<tensor_config_t> tensor_configs;
  165. if (hft >= offset_has_tensors) {
  166. tensor_configs = get_tensor_configs(rng);
  167. }
  168. if (hft == HANDCRAFTED_HEADER_BAD_N_TENSORS) {
  169. const uint64_t n_tensors = -1;
  170. helper_write(file, n_tensors);
  171. } else {
  172. const uint64_t n_tensors = tensor_configs.size();
  173. helper_write(file, n_tensors);
  174. }
  175. std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
  176. if (hft >= offset_has_kv) {
  177. kv_types = get_kv_types(rng);
  178. }
  179. {
  180. uint64_t n_kv = kv_types.size();
  181. if (hft == HANDCRAFTED_KV_BAD_ALIGN ||
  182. hft == HANDCRAFTED_TENSORS_BAD_ALIGN || hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN ||
  183. hft == HANDCRAFTED_DATA_BAD_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN) {
  184. n_kv += 1;
  185. } else if (hft == HANDCRAFTED_HEADER_BAD_N_KV) {
  186. n_kv = -1;
  187. }
  188. helper_write(file, n_kv);
  189. }
  190. if (hft < offset_has_kv) {
  191. while (ftell(file) % alignment != 0) {
  192. const char pad = 0;
  193. helper_write(file, pad);
  194. }
  195. for (int i = 0; i < extra_bytes; ++i) {
  196. const char tmp = 0;
  197. helper_write(file, tmp);
  198. }
  199. rewind(file);
  200. return file;
  201. }
  202. for (int i = 0; i < int(kv_types.size()); ++i) {
  203. const enum gguf_type type = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].first);
  204. const enum gguf_type type_arr = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].second);
  205. const std::string key = "my_key_" + std::to_string((hft == HANDCRAFTED_KV_DUPLICATE_KEY ? i/2 : i));
  206. if (hft == HANDCRAFTED_KV_BAD_KEY_SIZE) {
  207. const uint64_t n = -1;
  208. helper_write(file, n);
  209. } else {
  210. const uint64_t n = key.length();
  211. helper_write(file, n);
  212. }
  213. helper_write(file, key.data(), key.length());
  214. {
  215. const int32_t type32 = int32_t(type);
  216. helper_write(file, type32);
  217. }
  218. uint32_t data[16];
  219. for (int j = 0; j < 16; ++j) {
  220. data[j] = rng();
  221. if (type == GGUF_TYPE_STRING || type_arr == GGUF_TYPE_STRING) {
  222. data[j] |= 0x01010101; // avoid random null-termination of string
  223. }
  224. }
  225. if (type == GGUF_TYPE_STRING) {
  226. const uint64_t n = rng() % sizeof(data);
  227. helper_write(file, n);
  228. helper_write(file, data, n);
  229. continue;
  230. }
  231. if (type == GGUF_TYPE_ARRAY) {
  232. {
  233. const int32_t type32 = int32_t(type_arr);
  234. helper_write(file, type32);
  235. }
  236. if (type_arr == GGUF_TYPE_STRING) {
  237. const uint64_t nstr = rng() % (16 + 1);
  238. helper_write(file, nstr);
  239. for (uint64_t istr = 0; istr < nstr; ++istr) {
  240. const uint64_t n = rng() % (sizeof(uint32_t) + 1);
  241. helper_write(file, n);
  242. helper_write(file, &data[istr], n);
  243. }
  244. continue;
  245. }
  246. const size_t type_size = gguf_type_size(type_arr);
  247. const uint64_t n = (rng() % sizeof(data)) / type_size;
  248. helper_write(file, n);
  249. helper_write(file, &data, n*type_size);
  250. continue;
  251. }
  252. helper_write(file, data, hft == HANDCRAFTED_KV_BAD_TYPE ? 1 : gguf_type_size(type));
  253. }
  254. if (hft == HANDCRAFTED_KV_BAD_ALIGN ||
  255. hft == HANDCRAFTED_TENSORS_BAD_ALIGN || hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN ||
  256. hft == HANDCRAFTED_DATA_BAD_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN) {
  257. const uint64_t n = strlen(GGUF_KEY_GENERAL_ALIGNMENT);
  258. helper_write(file, n);
  259. helper_write(file, GGUF_KEY_GENERAL_ALIGNMENT, n);
  260. const int32_t type = gguf_type(GGUF_TYPE_UINT32);
  261. helper_write(file, type);
  262. alignment = expect_context_not_null(hft) ? 1 : 13;
  263. helper_write(file, alignment);
  264. }
  265. if (hft < offset_has_tensors) {
  266. while (ftell(file) % alignment != 0) {
  267. const char pad = 0;
  268. helper_write(file, pad);
  269. }
  270. for (int i = 0; i < extra_bytes; ++i) {
  271. const char tmp = 0;
  272. helper_write(file, tmp);
  273. }
  274. rewind(file);
  275. return file;
  276. }
  277. if (hft == HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN || hft == HANDCRAFTED_DATA_INCONSISTENT_ALIGN) {
  278. alignment = 1;
  279. }
  280. uint64_t offset = 0;
  281. for (int i = 0; i < int(tensor_configs.size()); ++i) {
  282. const ggml_type type = hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG ? GGML_TYPE_I64 : tensor_configs[i].first;
  283. const std::array<int64_t, GGML_MAX_DIMS> shape = tensor_configs[i].second;
  284. std::string name = "my_tensor";
  285. if (hft != HANDCRAFTED_TENSORS_DUPLICATE_NAME) {
  286. name += "_" + std::to_string(i);
  287. }
  288. if (hft == HANDCRAFTED_TENSORS_BAD_NAME_SIZE) {
  289. name += "_with_a_very_long_name_which_is_longer_than_what_is_allowed_for_ggml_tensors";
  290. GGML_ASSERT(name.length() >= GGML_MAX_NAME);
  291. }
  292. {
  293. const uint64_t n = name.length();
  294. helper_write(file, n);
  295. }
  296. helper_write(file, name.data(), name.length());
  297. uint32_t n_dims = (hft == HANDCRAFTED_TENSORS_NE_TOO_BIG || hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG) ? 2 : 1;
  298. for (int i = GGML_MAX_DIMS-1; i >= 1; --i) {
  299. if (shape[i] != 1) {
  300. n_dims = i + 1;
  301. break;
  302. }
  303. }
  304. if (hft == HANDCRAFTED_TENSORS_BAD_N_DIMS) {
  305. const uint32_t n_dims_bad = GGML_MAX_DIMS + 1;
  306. helper_write(file, n_dims_bad);
  307. } else {
  308. helper_write(file, n_dims);
  309. }
  310. if (hft == HANDCRAFTED_TENSORS_BAD_SHAPE) {
  311. const int64_t bad_dim = -1;
  312. for (uint32_t j = 0; j < n_dims; ++j) {
  313. helper_write(file, bad_dim);
  314. }
  315. } else if (hft == HANDCRAFTED_TENSORS_NE_TOO_BIG){
  316. const int64_t big_dim = 4*int64_t(INT32_MAX);
  317. for (uint32_t j = 0; j < n_dims; ++j) {
  318. helper_write(file, big_dim);
  319. }
  320. } else if (hft == HANDCRAFTED_TENSORS_NBYTES_TOO_BIG){
  321. const size_t big_ne = SIZE_MAX/ggml_type_size(type);
  322. const int64_t big_dim = GGML_PAD(int64_t(1.01f*std::pow(big_ne, 1.0f/n_dims)) + 1, ggml_blck_size(type));
  323. for (uint32_t j = 0; j < n_dims; ++j) {
  324. helper_write(file, big_dim);
  325. }
  326. } else {
  327. helper_write(file, shape.data(), n_dims*sizeof(int64_t));
  328. }
  329. {
  330. const int32_t type32 = hft == HANDCRAFTED_TENSORS_BAD_TYPE ? GGML_TYPE_COUNT : int32_t(type);
  331. helper_write(file, type32);
  332. }
  333. if (hft == HANDCRAFTED_TENSORS_BAD_OFFSET) {
  334. const uint64_t bad_offset = -1;
  335. helper_write(file, bad_offset);
  336. } else {
  337. helper_write(file, offset);
  338. }
  339. int64_t ne = shape[0];
  340. for (uint32_t i = 1; i < n_dims; ++i) {
  341. ne *= shape[i];
  342. }
  343. offset += GGML_PAD(ggml_row_size(type, ne), alignment);
  344. }
  345. while (ftell(file) % alignment != 0) {
  346. const char pad = 0;
  347. helper_write(file, pad);
  348. }
  349. if (hft >= offset_has_data) {
  350. rng.seed(seed + 1);
  351. uint64_t nbytes = offset;
  352. if (hft == HANDCRAFTED_DATA_NOT_ENOUGH_DATA) {
  353. nbytes -= 1;
  354. }
  355. for (uint64_t i = 0; i < nbytes; ++i) {
  356. const uint8_t random_byte = i % 256;
  357. helper_write(file, random_byte);
  358. }
  359. }
  360. for (int i = 0; i < extra_bytes; ++i) {
  361. const char tmp = 0;
  362. helper_write(file, tmp);
  363. }
  364. rewind(file);
  365. return file;
  366. }
  367. static 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) {
  368. if (!gguf_ctx) {
  369. return false;
  370. }
  371. std::mt19937 rng(seed);
  372. std::vector<tensor_config_t> tensor_configs;
  373. if (has_tensors) {
  374. tensor_configs = get_tensor_configs(rng);
  375. }
  376. std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
  377. if (has_kv) {
  378. kv_types = get_kv_types(rng);
  379. }
  380. bool ok = true;
  381. if (gguf_get_version(gguf_ctx) != GGUF_VERSION) {
  382. ok = false;
  383. }
  384. if (gguf_get_n_tensors(gguf_ctx) != int(tensor_configs.size())) {
  385. ok = false;
  386. }
  387. if (gguf_get_n_kv(gguf_ctx) != int(alignment_defined ? kv_types.size() + 1 : kv_types.size())) {
  388. ok = false;
  389. }
  390. return ok;
  391. }
  392. static bool handcrafted_check_kv(const gguf_context * gguf_ctx, const unsigned int seed, const bool has_tensors, const bool alignment_defined) {
  393. if (!gguf_ctx) {
  394. return false;
  395. }
  396. std::mt19937 rng(seed);
  397. std::vector<tensor_config_t> tensor_configs;
  398. if (has_tensors) {
  399. tensor_configs = get_tensor_configs(rng);
  400. }
  401. std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types = get_kv_types(rng);
  402. bool ok = true;
  403. for (int i = 0; i < int(kv_types.size()); ++i) {
  404. const enum gguf_type type = gguf_type(kv_types[i].first);
  405. const enum gguf_type type_arr = gguf_type(kv_types[i].second);
  406. const std::string key = "my_key_" + std::to_string(i);
  407. uint32_t data[16];
  408. for (int j = 0; j < 16; ++j) {
  409. data[j] = rng();
  410. if (type == GGUF_TYPE_STRING || type_arr == GGUF_TYPE_STRING) {
  411. data[j] |= 0x01010101; // avoid random null-termination of string
  412. }
  413. }
  414. const char * data8 = reinterpret_cast<const char *>(data);
  415. const int id = gguf_find_key(gguf_ctx, key.c_str());
  416. if (type == GGUF_TYPE_STRING) {
  417. const char * str = gguf_get_val_str(gguf_ctx, id);
  418. const uint64_t n = strlen(str);
  419. const uint64_t n_expected = rng() % sizeof(data);
  420. if (n != n_expected) {
  421. ok = false;
  422. continue;
  423. }
  424. if (!std::equal(str, str + n, data8)) {
  425. ok = false;
  426. }
  427. continue;
  428. }
  429. if (type == GGUF_TYPE_ARRAY) {
  430. const size_t type_size = gguf_type_size(type_arr);
  431. const uint64_t arr_n = gguf_get_arr_n(gguf_ctx, id);
  432. if (type_arr == GGUF_TYPE_STRING) {
  433. const uint64_t nstr_expected = rng() % (16 + 1);
  434. if (arr_n != nstr_expected) {
  435. ok = false;
  436. continue;
  437. }
  438. for (uint64_t istr = 0; istr < nstr_expected; ++istr) {
  439. const char * str = gguf_get_arr_str(gguf_ctx, id, istr);
  440. const uint64_t n = strlen(str);
  441. const uint64_t n_expected = rng() % (sizeof(uint32_t) + 1);
  442. if (n != n_expected) {
  443. ok = false;
  444. continue;
  445. }
  446. const char * str_expected = reinterpret_cast<const char *>(&data[istr]);
  447. if (strncmp(str, str_expected, n) != 0) {
  448. ok = false;
  449. continue;
  450. }
  451. }
  452. continue;
  453. }
  454. const uint64_t arr_n_expected = (rng() % sizeof(data)) / type_size;
  455. if (arr_n != arr_n_expected) {
  456. ok = false;
  457. continue;
  458. }
  459. const char * data_gguf = reinterpret_cast<const char *>(gguf_get_arr_data(gguf_ctx, id));
  460. if (type_arr == GGUF_TYPE_BOOL) {
  461. for (size_t arr_i = 0; arr_i < arr_n; ++arr_i) {
  462. if (bool(data8[arr_i]) != bool(data_gguf[arr_i])) {
  463. ok = false;
  464. }
  465. }
  466. continue;
  467. }
  468. if (!std::equal(data8, data8 + arr_n*type_size, data_gguf)) {
  469. ok = false;
  470. }
  471. continue;
  472. }
  473. const char * data_gguf = reinterpret_cast<const char *>(gguf_get_val_data(gguf_ctx, id));
  474. if (type == GGUF_TYPE_BOOL) {
  475. if (bool(*data8) != bool(*data_gguf)) {
  476. ok = false;
  477. }
  478. continue;
  479. }
  480. if (!std::equal(data8, data8 + gguf_type_size(type), data_gguf)) {
  481. ok = false;
  482. }
  483. }
  484. const uint32_t expected_alignment = alignment_defined ? 1 : GGUF_DEFAULT_ALIGNMENT;
  485. if (gguf_get_alignment(gguf_ctx) != expected_alignment) {
  486. ok = false;
  487. }
  488. return ok;
  489. }
  490. static bool handcrafted_check_tensors(const gguf_context * gguf_ctx, const unsigned int seed) {
  491. if (!gguf_ctx) {
  492. return false;
  493. }
  494. std::mt19937 rng(seed);
  495. std::vector<tensor_config_t> tensor_configs = get_tensor_configs(rng);
  496. // Call get_kv_types to get the same RNG state:
  497. get_kv_types(rng);
  498. bool ok = true;
  499. const int id_alignment = gguf_find_key(gguf_ctx, GGUF_KEY_GENERAL_ALIGNMENT);
  500. const uint32_t alignment = id_alignment >= 0 ? gguf_get_val_u32(gguf_ctx, id_alignment) : GGUF_DEFAULT_ALIGNMENT;
  501. uint64_t expected_offset = 0;
  502. for (int i = 0; i < int(tensor_configs.size()); ++i) {
  503. const ggml_type type = tensor_configs[i].first;
  504. const std::array<int64_t, GGML_MAX_DIMS> shape = tensor_configs[i].second;
  505. const std::string name = "my_tensor_" + std::to_string(i);
  506. const int id = gguf_find_tensor(gguf_ctx, name.c_str());
  507. if (id >= 0) {
  508. if (std::string(gguf_get_tensor_name(gguf_ctx, id)) != name) {
  509. ok = false;
  510. }
  511. if (gguf_get_tensor_type(gguf_ctx, id) != type) {
  512. ok = false;
  513. }
  514. } else {
  515. ok = false;
  516. continue;
  517. }
  518. const size_t offset = gguf_get_tensor_offset(gguf_ctx, id);
  519. if (offset != expected_offset) {
  520. ok = false;
  521. }
  522. int64_t ne = shape[0];
  523. for (size_t j = 1; j < GGML_MAX_DIMS; ++j) {
  524. ne *= shape[j];
  525. }
  526. expected_offset += GGML_PAD(ggml_row_size(type, ne), alignment);
  527. }
  528. return ok;
  529. }
  530. static bool handcrafted_check_tensor_data(const gguf_context * gguf_ctx, const unsigned int seed, FILE * file) {
  531. if (!gguf_ctx) {
  532. return false;
  533. }
  534. std::mt19937 rng(seed);
  535. std::vector<tensor_config_t> tensor_configs = get_tensor_configs(rng);
  536. bool ok = true;
  537. for (int i = 0; i < int(tensor_configs.size()); ++i) {
  538. const ggml_type type = tensor_configs[i].first;
  539. const std::array<int64_t, GGML_MAX_DIMS> shape = tensor_configs[i].second;
  540. int64_t ne = shape[0];
  541. for (size_t j = 1; j < GGML_MAX_DIMS; ++j) {
  542. ne *= shape[j];
  543. }
  544. const size_t size = ggml_row_size(type, ne);
  545. const std::string name = "my_tensor_" + std::to_string(i);
  546. const size_t offset = gguf_get_tensor_offset(gguf_ctx, gguf_find_tensor(gguf_ctx, name.c_str()));
  547. std::vector<uint8_t> data(size);
  548. GGML_ASSERT(fseek(file, gguf_get_data_offset(gguf_ctx) + offset, SEEK_SET) == 0);
  549. GGML_ASSERT(fread(data.data(), 1, data.size(), file) == data.size());
  550. for (size_t j = 0; j < size; ++j) {
  551. const uint8_t expected_byte = (j + offset) % 256;
  552. if (data[j] != expected_byte) {
  553. ok = false;
  554. }
  555. }
  556. }
  557. return ok;
  558. }
  559. static std::pair<int, int> test_handcrafted_file(const unsigned int seed) {
  560. int npass = 0;
  561. int ntest = 0;
  562. const std::vector<handcrafted_file_type> hfts = {
  563. HANDCRAFTED_HEADER_BAD_MAGIC,
  564. HANDCRAFTED_HEADER_BAD_VERSION_0,
  565. HANDCRAFTED_HEADER_BAD_VERSION_1,
  566. HANDCRAFTED_HEADER_BAD_VERSION_FUTURE,
  567. HANDCRAFTED_HEADER_BAD_N_KV,
  568. HANDCRAFTED_HEADER_BAD_N_TENSORS,
  569. HANDCRAFTED_HEADER_EMPTY,
  570. HANDCRAFTED_KV_BAD_KEY_SIZE,
  571. HANDCRAFTED_KV_BAD_TYPE,
  572. HANDCRAFTED_KV_DUPLICATE_KEY,
  573. HANDCRAFTED_KV_BAD_ALIGN,
  574. HANDCRAFTED_KV_SUCCESS,
  575. HANDCRAFTED_TENSORS_BAD_NAME_SIZE,
  576. HANDCRAFTED_TENSORS_BAD_N_DIMS,
  577. HANDCRAFTED_TENSORS_BAD_SHAPE,
  578. HANDCRAFTED_TENSORS_NE_TOO_BIG,
  579. HANDCRAFTED_TENSORS_NBYTES_TOO_BIG,
  580. HANDCRAFTED_TENSORS_BAD_TYPE,
  581. HANDCRAFTED_TENSORS_BAD_OFFSET,
  582. HANDCRAFTED_TENSORS_DUPLICATE_NAME,
  583. HANDCRAFTED_TENSORS_BAD_ALIGN,
  584. HANDCRAFTED_TENSORS_INCONSISTENT_ALIGN,
  585. HANDCRAFTED_TENSORS_SUCCESS,
  586. HANDCRAFTED_TENSORS_CUSTOM_ALIGN,
  587. HANDCRAFTED_DATA_NOT_ENOUGH_DATA,
  588. HANDCRAFTED_DATA_BAD_ALIGN,
  589. HANDCRAFTED_DATA_INCONSISTENT_ALIGN,
  590. HANDCRAFTED_DATA_SUCCESS,
  591. HANDCRAFTED_DATA_CUSTOM_ALIGN,
  592. };
  593. for (enum handcrafted_file_type hft : hfts) {
  594. printf("%s: handcrafted_file_type=%s\n", __func__, handcrafted_file_type_name(hft).c_str());
  595. FILE * file = get_handcrafted_file(seed, hft);
  596. #ifdef _WIN32
  597. if (!file) {
  598. printf("failed to create tmpfile(), needs elevated privileges on Windows");
  599. printf("skipping tests");
  600. continue;
  601. }
  602. #else
  603. GGML_ASSERT(file);
  604. #endif // _WIN32
  605. struct ggml_context * ctx = nullptr;
  606. struct gguf_init_params gguf_params = {
  607. /*no_alloc =*/ false,
  608. /*ctx =*/ hft >= offset_has_data ? &ctx : nullptr,
  609. };
  610. struct gguf_context * gguf_ctx = gguf_init_from_file_impl(file, gguf_params);
  611. if (expect_context_not_null(hft)) {
  612. printf("%s: - context_not_null: ", __func__);
  613. } else {
  614. printf("%s: - context_null: ", __func__);
  615. }
  616. if (bool(gguf_ctx) == expect_context_not_null(hft)) {
  617. printf("\033[1;32mOK\033[0m\n");
  618. npass++;
  619. } else {
  620. printf("\033[1;31mFAIL\033[0m\n");
  621. }
  622. ntest++;
  623. if (hft >= offset_has_data && !expect_context_not_null(hft)) {
  624. printf("%s: - no_dangling_ggml_context_pointer: ", __func__);
  625. if (ctx) {
  626. printf("\033[1;31mFAIL\033[0m\n");
  627. } else {
  628. printf("\033[1;32mOK\033[0m\n");
  629. npass++;
  630. }
  631. ntest++;
  632. }
  633. const bool alignment_defined = hft == HANDCRAFTED_TENSORS_CUSTOM_ALIGN || hft == HANDCRAFTED_DATA_CUSTOM_ALIGN;
  634. if (expect_context_not_null(hft)) {
  635. printf("%s: - check_header: ", __func__);
  636. if (handcrafted_check_header(gguf_ctx, seed, hft >= offset_has_kv, hft >= offset_has_tensors, alignment_defined)) {
  637. printf("\033[1;32mOK\033[0m\n");
  638. npass++;
  639. } else {
  640. printf("\033[1;31mFAIL\033[0m\n");
  641. }
  642. ntest++;
  643. }
  644. if (expect_context_not_null(hft) && hft >= offset_has_kv) {
  645. printf("%s: - check_kv: ", __func__);
  646. if (handcrafted_check_kv(gguf_ctx, seed, hft >= offset_has_tensors, alignment_defined)) {
  647. printf("\033[1;32mOK\033[0m\n");
  648. npass++;
  649. } else {
  650. printf("\033[1;31mFAIL\033[0m\n");
  651. }
  652. ntest++;
  653. }
  654. if (expect_context_not_null(hft) && hft >= offset_has_tensors) {
  655. printf("%s: - check_tensors: ", __func__);
  656. if (handcrafted_check_tensors(gguf_ctx, seed)) {
  657. printf("\033[1;32mOK\033[0m\n");
  658. npass++;
  659. } else {
  660. printf("\033[1;31mFAIL\033[0m\n");
  661. }
  662. ntest++;
  663. }
  664. if (expect_context_not_null(hft) && hft >= offset_has_data) {
  665. printf("%s: - check_tensor_data: ", __func__);
  666. if (handcrafted_check_tensor_data(gguf_ctx, seed, file)) {
  667. printf("\033[1;32mOK\033[0m\n");
  668. npass++;
  669. } else {
  670. printf("\033[1;31mFAIL\033[0m\n");
  671. }
  672. ntest++;
  673. }
  674. fclose(file);
  675. if (gguf_ctx) {
  676. ggml_free(ctx);
  677. gguf_free(gguf_ctx);
  678. }
  679. printf("\n");
  680. }
  681. return std::make_pair(npass, ntest);
  682. }
  683. struct random_gguf_context_result {
  684. struct gguf_context * gguf_ctx;
  685. struct ggml_context * ctx;
  686. ggml_backend_buffer_t buffer;
  687. };
  688. static struct random_gguf_context_result get_random_gguf_context(ggml_backend_t backend, const unsigned int seed) {
  689. std::mt19937 rng(seed);
  690. struct gguf_context * gguf_ctx = gguf_init_empty();
  691. for (int i = 0; i < 256; ++i) {
  692. const std::string key = "my_key_" + std::to_string(rng() % 1024);
  693. const enum gguf_type type = gguf_type(rng() % GGUF_TYPE_COUNT);
  694. switch (type) {
  695. case GGUF_TYPE_UINT8: gguf_set_val_u8 (gguf_ctx, key.c_str(), rng() % (1 << 7)); break;
  696. case GGUF_TYPE_INT8: gguf_set_val_i8 (gguf_ctx, key.c_str(), rng() % (1 << 7) - (1 << 6)); break;
  697. case GGUF_TYPE_UINT16: gguf_set_val_u16 (gguf_ctx, key.c_str(), rng() % (1 << 15)); break;
  698. case GGUF_TYPE_INT16: gguf_set_val_i16 (gguf_ctx, key.c_str(), rng() % (1 << 15) - (1 << 14)); break;
  699. case GGUF_TYPE_UINT32: gguf_set_val_u32 (gguf_ctx, key.c_str(), rng()); break;
  700. case GGUF_TYPE_INT32: gguf_set_val_i32 (gguf_ctx, key.c_str(), rng() - (1 << 30)); break;
  701. case GGUF_TYPE_FLOAT32: gguf_set_val_f32 (gguf_ctx, key.c_str(), rng() % 1024 - 512); break;
  702. case GGUF_TYPE_BOOL: gguf_set_val_bool(gguf_ctx, key.c_str(), rng() % 2 == 0); break;
  703. case GGUF_TYPE_STRING: gguf_set_val_str (gguf_ctx, key.c_str(), std::to_string(rng()).c_str()); break;
  704. case GGUF_TYPE_UINT64: gguf_set_val_u64 (gguf_ctx, key.c_str(), rng()); break;
  705. case GGUF_TYPE_INT64: gguf_set_val_i64 (gguf_ctx, key.c_str(), rng() - (1 << 30)); break;
  706. case GGUF_TYPE_FLOAT64: gguf_set_val_f32 (gguf_ctx, key.c_str(), rng() % 1024 - 512); break;
  707. case GGUF_TYPE_ARRAY: {
  708. const enum gguf_type type_arr = gguf_type(rng() % GGUF_TYPE_COUNT);
  709. const uint64_t ne = rng() % 1024;
  710. switch (type_arr) {
  711. case GGUF_TYPE_UINT8:
  712. case GGUF_TYPE_INT8:
  713. case GGUF_TYPE_UINT16:
  714. case GGUF_TYPE_INT16:
  715. case GGUF_TYPE_UINT32:
  716. case GGUF_TYPE_INT32:
  717. case GGUF_TYPE_FLOAT32:
  718. case GGUF_TYPE_BOOL:
  719. case GGUF_TYPE_UINT64:
  720. case GGUF_TYPE_INT64:
  721. case GGUF_TYPE_FLOAT64: {
  722. const size_t nbytes = ne*gguf_type_size(type_arr);
  723. std::vector<uint32_t> random_data((nbytes + sizeof(uint32_t) - 1) / sizeof(uint32_t));
  724. for (size_t j = 0; j < random_data.size(); ++j) {
  725. random_data[j] = rng();
  726. if (type_arr == GGUF_TYPE_BOOL) {
  727. random_data[j] &= 0x01010101; // the sanitizer complains if booleans are not 0 or 1
  728. }
  729. }
  730. gguf_set_arr_data(gguf_ctx, key.c_str(), type_arr, random_data.data(), ne);
  731. } break;
  732. case GGUF_TYPE_STRING: {
  733. std::vector<std::string> data_cpp(ne);
  734. std::vector<const char *> data_c(ne);
  735. for (size_t j = 0; j < data_cpp.size(); ++j) {
  736. data_cpp[j] = std::to_string(rng());
  737. data_c[j] = data_cpp[j].c_str();
  738. }
  739. gguf_set_arr_str(gguf_ctx, key.c_str(), data_c.data(), ne);
  740. } break;
  741. case GGUF_TYPE_ARRAY: {
  742. break; // not supported
  743. }
  744. case GGUF_TYPE_COUNT:
  745. default: {
  746. GGML_ABORT("fatal error");
  747. }
  748. }
  749. } break;
  750. case GGUF_TYPE_COUNT:
  751. default: {
  752. GGML_ABORT("fatal error");
  753. }
  754. }
  755. }
  756. struct ggml_init_params ggml_params = {
  757. /*.mem_size =*/ 256*ggml_tensor_overhead(),
  758. /*.mem_buffer =*/ nullptr,
  759. /*.no_alloc =*/ true,
  760. };
  761. struct ggml_context * ctx = ggml_init(ggml_params);
  762. for (int i = 0; i < 256; ++i) {
  763. const std::string name = "my_tensor_" + std::to_string(i);
  764. const enum ggml_type type = ggml_type(rng() % GGML_TYPE_COUNT);
  765. const size_t type_size = ggml_type_size(type);
  766. if (type_size == 0) {
  767. continue;
  768. }
  769. const int n_dims = 1 + rng() % GGML_MAX_DIMS;
  770. int64_t ne[GGML_MAX_DIMS];
  771. ne[0] = (1 + rng() % 10) * ggml_blck_size(type);
  772. for (int j = 1; j < n_dims; ++j) {
  773. ne[j] = 1 + rng() % 10;
  774. }
  775. struct ggml_tensor * tensor = ggml_new_tensor(ctx, type, n_dims, ne);
  776. ggml_set_name(tensor, name.c_str());
  777. }
  778. ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors(ctx, backend);
  779. for (struct ggml_tensor * t = ggml_get_first_tensor(ctx); t != nullptr; t = ggml_get_next_tensor(ctx, t)) {
  780. const size_t nbytes = ggml_nbytes(t);
  781. std::vector<uint32_t> random_data((nbytes + sizeof(uint32_t) - 1) / sizeof(uint32_t));
  782. for (size_t j = 0; j < random_data.size(); ++j) {
  783. random_data[j] = rng();
  784. }
  785. ggml_backend_tensor_set(t, random_data.data(), 0, nbytes);
  786. gguf_add_tensor(gguf_ctx, t);
  787. }
  788. return {gguf_ctx, ctx, buf};
  789. }
  790. static bool all_kv_in_other(const gguf_context * ctx, const gguf_context * other) {
  791. bool ok = true;
  792. const int n_kv = gguf_get_n_kv(ctx);
  793. for (int id = 0; id < n_kv; ++id) {
  794. const char * name = gguf_get_key(ctx, id);
  795. const int idx_other = gguf_find_key(other, name);
  796. if (idx_other < 0) {
  797. ok = false;
  798. continue;
  799. }
  800. const gguf_type type = gguf_get_kv_type(ctx, id);
  801. if (type != gguf_get_kv_type(other, idx_other)) {
  802. ok = false;
  803. continue;
  804. }
  805. if (type == GGUF_TYPE_ARRAY) {
  806. const size_t arr_n = gguf_get_arr_n(ctx, id);
  807. if (arr_n != gguf_get_arr_n(other, idx_other)) {
  808. ok = false;
  809. continue;
  810. }
  811. const gguf_type type_arr = gguf_get_arr_type(ctx, id);
  812. if (type_arr != gguf_get_arr_type(other, idx_other)) {
  813. ok = false;
  814. continue;
  815. }
  816. if (type_arr == GGUF_TYPE_BOOL) {
  817. const int8_t * data = reinterpret_cast<const int8_t *>(gguf_get_arr_data(ctx, id));
  818. const int8_t * data_other = reinterpret_cast<const int8_t *>(gguf_get_arr_data(other, idx_other));
  819. for (size_t arr_i = 0; arr_i < arr_n; ++arr_i) {
  820. if (bool(data[arr_i]) != bool(data_other[arr_i])) {
  821. ok = false;
  822. }
  823. }
  824. continue;
  825. }
  826. if (type_arr == GGUF_TYPE_STRING) {
  827. for (size_t arr_i = 0; arr_i < arr_n; ++arr_i) {
  828. const std::string str = gguf_get_arr_str(ctx, id, arr_i);
  829. const std::string str_other = gguf_get_arr_str(other, idx_other, arr_i);
  830. if (str != str_other) {
  831. ok = false;
  832. }
  833. }
  834. continue;
  835. }
  836. const int8_t * data = reinterpret_cast<const int8_t *>(gguf_get_arr_data(ctx, id));
  837. const int8_t * data_other = reinterpret_cast<const int8_t *>(gguf_get_arr_data(other, idx_other));
  838. if (!std::equal(data, data + arr_n*gguf_type_size(type_arr), data_other)) {
  839. ok = false;
  840. }
  841. continue;
  842. }
  843. if (type == GGUF_TYPE_STRING) {
  844. const std::string str = gguf_get_val_str(ctx, id);
  845. const std::string str_other = gguf_get_val_str(other, idx_other);
  846. if (str != str_other) {
  847. ok = false;
  848. }
  849. continue;
  850. }
  851. const char * data = reinterpret_cast<const char *>(gguf_get_val_data(ctx, id));
  852. const char * data_other = reinterpret_cast<const char *>(gguf_get_val_data(other, idx_other));
  853. if (!std::equal(data, data + gguf_type_size(type), data_other)) {
  854. ok = false;
  855. }
  856. }
  857. return ok;
  858. }
  859. static bool all_tensors_in_other(const gguf_context * ctx, const gguf_context * other) {
  860. bool ok = true;
  861. const int n_tensors = gguf_get_n_tensors(ctx);
  862. for (int id = 0; id < n_tensors; ++id) {
  863. const std::string name = gguf_get_tensor_name(ctx, id);
  864. const int idx_other = gguf_find_tensor(other, name.c_str());
  865. if (id != idx_other) {
  866. ok = false;
  867. if (idx_other < 0) {
  868. continue;
  869. }
  870. }
  871. const ggml_type type = gguf_get_tensor_type(ctx, id);
  872. if (type != gguf_get_tensor_type(other, id)) {
  873. ok = false;
  874. }
  875. const size_t offset = gguf_get_tensor_offset(ctx, id);
  876. if (offset != gguf_get_tensor_offset(other, id)) {
  877. ok = false;
  878. }
  879. }
  880. return ok;
  881. }
  882. static bool same_tensor_data(const struct ggml_context * orig, const struct ggml_context * read) {
  883. bool ok = true;
  884. struct ggml_tensor * t_orig = ggml_get_first_tensor(orig);
  885. struct ggml_tensor * t_read = ggml_get_first_tensor(read);
  886. if (std::string(t_read->name) != "GGUF tensor data binary blob") {
  887. return false;
  888. }
  889. t_read = ggml_get_next_tensor(read, t_read);
  890. while (t_orig) {
  891. if (!t_read) {
  892. ok = false;
  893. break;
  894. }
  895. const size_t nbytes = ggml_nbytes(t_orig);
  896. if (ggml_nbytes(t_read) != nbytes) {
  897. ok = false;
  898. break;
  899. }
  900. std::vector<char> data_orig(nbytes);
  901. ggml_backend_tensor_get(t_orig, data_orig.data(), 0, nbytes);
  902. if (!std::equal(data_orig.data(), data_orig.data() + nbytes, reinterpret_cast<const char *>(t_read->data))) {
  903. ok = false;
  904. }
  905. t_orig = ggml_get_next_tensor(orig, t_orig);
  906. t_read = ggml_get_next_tensor(read, t_read);
  907. }
  908. if (t_read) {
  909. ok = false;
  910. }
  911. return ok;
  912. }
  913. static std::pair<int, int> test_roundtrip(ggml_backend_dev_t dev, const unsigned int seed, const bool only_meta) {
  914. ggml_backend_t backend = ggml_backend_dev_init(dev, nullptr);
  915. printf("%s: device=%s, backend=%s, only_meta=%s\n",
  916. __func__, ggml_backend_dev_description(dev), ggml_backend_name(backend), only_meta ? "yes" : "no");
  917. int npass = 0;
  918. int ntest = 0;
  919. struct gguf_context * gguf_ctx_0;
  920. struct ggml_context * ctx_0;
  921. ggml_backend_buffer_t bbuf;
  922. {
  923. struct random_gguf_context_result result = get_random_gguf_context(backend, seed);
  924. gguf_ctx_0 = result.gguf_ctx;
  925. ctx_0 = result.ctx;
  926. bbuf = result.buffer;
  927. }
  928. FILE * file = tmpfile();
  929. #ifdef _WIN32
  930. if (!file) {
  931. printf("failed to create tmpfile(), needs elevated privileges on Windows");
  932. printf("skipping tests");
  933. return std::make_pair(0, 0);
  934. }
  935. #else
  936. GGML_ASSERT(file);
  937. #endif // _WIN32
  938. {
  939. std::vector<int8_t> buf;
  940. gguf_write_to_buf(gguf_ctx_0, buf, only_meta);
  941. GGML_ASSERT(fwrite(buf.data(), 1, buf.size(), file) == buf.size());
  942. rewind(file);
  943. }
  944. struct ggml_context * ctx_1 = nullptr;
  945. struct gguf_init_params gguf_params = {
  946. /*no_alloc =*/ false,
  947. /*ctx =*/ only_meta ? nullptr : &ctx_1,
  948. };
  949. struct gguf_context * gguf_ctx_1 = gguf_init_from_file_impl(file, gguf_params);
  950. printf("%s: same_version: ", __func__);
  951. if (gguf_get_version(gguf_ctx_0) == gguf_get_version(gguf_ctx_1)) {
  952. printf("\033[1;32mOK\033[0m\n");
  953. npass++;
  954. } else {
  955. printf("\033[1;31mFAIL\033[0m\n");
  956. }
  957. ntest++;
  958. printf("%s: same_n_kv: ", __func__);
  959. if (gguf_get_n_kv(gguf_ctx_0) == gguf_get_n_kv(gguf_ctx_1)) {
  960. printf("\033[1;32mOK\033[0m\n");
  961. npass++;
  962. } else {
  963. printf("\033[1;31mFAIL\033[0m\n");
  964. }
  965. ntest++;
  966. printf("%s: same_n_tensors: ", __func__);
  967. if (gguf_get_n_tensors(gguf_ctx_0) == gguf_get_n_tensors(gguf_ctx_1)) {
  968. printf("\033[1;32mOK\033[0m\n");
  969. npass++;
  970. } else {
  971. printf("\033[1;31mFAIL\033[0m\n");
  972. }
  973. ntest++;
  974. printf("%s: all_orig_kv_in_read: ", __func__);
  975. if (all_kv_in_other(gguf_ctx_0, gguf_ctx_1)) {
  976. printf("\033[1;32mOK\033[0m\n");
  977. npass++;
  978. } else {
  979. printf("\033[1;31mFAIL\033[0m\n");
  980. }
  981. ntest++;
  982. printf("%s: all_read_kv_in_orig: ", __func__);
  983. if (all_kv_in_other(gguf_ctx_1, gguf_ctx_0)) {
  984. printf("\033[1;32mOK\033[0m\n");
  985. npass++;
  986. } else {
  987. printf("\033[1;31mFAIL\033[0m\n");
  988. }
  989. ntest++;
  990. printf("%s: all_orig_tensors_in_read: ", __func__);
  991. if (all_tensors_in_other(gguf_ctx_0, gguf_ctx_1)) {
  992. printf("\033[1;32mOK\033[0m\n");
  993. npass++;
  994. } else {
  995. printf("\033[1;31mFAIL\033[0m\n");
  996. }
  997. ntest++;
  998. printf("%s: all_read_tensors_in_orig: ", __func__);
  999. if (all_tensors_in_other(gguf_ctx_1, gguf_ctx_0)) {
  1000. printf("\033[1;32mOK\033[0m\n");
  1001. npass++;
  1002. } else {
  1003. printf("\033[1;31mFAIL\033[0m\n");
  1004. }
  1005. ntest++;
  1006. if (!only_meta) {
  1007. printf("%s: same_tensor_data: ", __func__);
  1008. if (same_tensor_data(ctx_0, ctx_1)) {
  1009. printf("\033[1;32mOK\033[0m\n");
  1010. npass++;
  1011. } else {
  1012. printf("\033[1;31mFAIL\033[0m\n");
  1013. }
  1014. ntest++;
  1015. }
  1016. ggml_backend_buffer_free(bbuf);
  1017. ggml_free(ctx_0);
  1018. ggml_free(ctx_1);
  1019. gguf_free(gguf_ctx_0);
  1020. gguf_free(gguf_ctx_1);
  1021. ggml_backend_free(backend);
  1022. fclose(file);
  1023. printf("\n");
  1024. return std::make_pair(npass, ntest);
  1025. }
  1026. static std::pair<int, int> test_gguf_set_kv(ggml_backend_dev_t dev, const unsigned int seed) {
  1027. ggml_backend_t backend = ggml_backend_dev_init(dev, nullptr);
  1028. printf("%s: device=%s, backend=%s\n", __func__, ggml_backend_dev_description(dev), ggml_backend_name(backend));
  1029. int npass = 0;
  1030. int ntest = 0;
  1031. struct gguf_context * gguf_ctx_0;
  1032. struct ggml_context * ctx_0;
  1033. ggml_backend_buffer_t bbuf_0;
  1034. {
  1035. struct random_gguf_context_result result = get_random_gguf_context(backend, seed);
  1036. gguf_ctx_0 = result.gguf_ctx;
  1037. ctx_0 = result.ctx;
  1038. bbuf_0 = result.buffer;
  1039. }
  1040. struct gguf_context * gguf_ctx_1;
  1041. struct ggml_context * ctx_1;
  1042. ggml_backend_buffer_t bbuf_1;
  1043. {
  1044. struct random_gguf_context_result result = get_random_gguf_context(backend, seed + 1);
  1045. gguf_ctx_1 = result.gguf_ctx;
  1046. ctx_1 = result.ctx;
  1047. bbuf_1 = result.buffer;
  1048. }
  1049. struct gguf_context * gguf_ctx_2 = gguf_init_empty();
  1050. gguf_set_kv(gguf_ctx_1, gguf_ctx_0);
  1051. gguf_set_kv(gguf_ctx_2, gguf_ctx_0);
  1052. printf("%s: same_n_kv: ", __func__);
  1053. if (gguf_get_n_kv(gguf_ctx_0) == gguf_get_n_kv(gguf_ctx_2)) {
  1054. printf("\033[1;32mOK\033[0m\n");
  1055. npass++;
  1056. } else {
  1057. printf("\033[1;31mFAIL\033[0m\n");
  1058. }
  1059. ntest++;
  1060. printf("%s: all_kv_0_in_1: ", __func__);
  1061. if (all_kv_in_other(gguf_ctx_0, gguf_ctx_1)) {
  1062. printf("\033[1;32mOK\033[0m\n");
  1063. npass++;
  1064. } else {
  1065. printf("\033[1;31mFAIL\033[0m\n");
  1066. }
  1067. ntest++;
  1068. printf("%s: all_kv_0_in_2: ", __func__);
  1069. if (all_kv_in_other(gguf_ctx_0, gguf_ctx_2)) {
  1070. printf("\033[1;32mOK\033[0m\n");
  1071. npass++;
  1072. } else {
  1073. printf("\033[1;31mFAIL\033[0m\n");
  1074. }
  1075. ntest++;
  1076. gguf_set_kv(gguf_ctx_0, gguf_ctx_1);
  1077. printf("%s: same_n_kv_after_double_copy: ", __func__);
  1078. if (gguf_get_n_kv(gguf_ctx_0) == gguf_get_n_kv(gguf_ctx_1)) {
  1079. printf("\033[1;32mOK\033[0m\n");
  1080. npass++;
  1081. } else {
  1082. printf("\033[1;31mFAIL\033[0m\n");
  1083. }
  1084. ntest++;
  1085. printf("%s: all_kv_1_in_0_after_double_copy: ", __func__);
  1086. if (all_kv_in_other(gguf_ctx_1, gguf_ctx_0)) {
  1087. printf("\033[1;32mOK\033[0m\n");
  1088. npass++;
  1089. } else {
  1090. printf("\033[1;31mFAIL\033[0m\n");
  1091. }
  1092. ntest++;
  1093. ggml_backend_buffer_free(bbuf_0);
  1094. ggml_backend_buffer_free(bbuf_1);
  1095. ggml_free(ctx_0);
  1096. ggml_free(ctx_1);
  1097. gguf_free(gguf_ctx_0);
  1098. gguf_free(gguf_ctx_1);
  1099. gguf_free(gguf_ctx_2);
  1100. ggml_backend_free(backend);
  1101. printf("\n");
  1102. return std::make_pair(npass, ntest);
  1103. }
  1104. static void print_usage() {
  1105. printf("usage: test-gguf [seed]\n");
  1106. printf(" if no seed is unspecified then a random seed is used\n");
  1107. }
  1108. int main(int argc, char ** argv) {
  1109. if (argc > 2) {
  1110. print_usage();
  1111. return 1;
  1112. }
  1113. std::random_device rd;
  1114. const unsigned int seed = argc < 2 ? rd() : std::stoi(argv[1]);
  1115. // Initialize ggml backends early so the prints aren't interleaved with the test results:
  1116. ggml_backend_dev_count();
  1117. fprintf(stderr, "\n");
  1118. int npass = 0;
  1119. int ntest = 0;
  1120. {
  1121. std::pair<int, int> result = test_handcrafted_file(seed);
  1122. npass += result.first;
  1123. ntest += result.second;
  1124. }
  1125. for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
  1126. ggml_backend_dev_t dev = ggml_backend_dev_get(i);
  1127. for (bool only_meta : {true, false}) {
  1128. std::pair<int, int> result = test_roundtrip(dev, seed, only_meta);
  1129. npass += result.first;
  1130. ntest += result.second;
  1131. }
  1132. {
  1133. std::pair<int, int> result = test_gguf_set_kv(dev, seed);
  1134. npass += result.first;
  1135. ntest += result.second;
  1136. }
  1137. }
  1138. printf("%d/%d tests passed\n", npass, ntest);
  1139. if (npass != ntest) {
  1140. printf("\033[1;31mFAIL\033[0m\n");
  1141. return 1;
  1142. }
  1143. printf("\033[1;32mOK\033[0m\n");
  1144. return 0;
  1145. }