Loads GGUF metadata and optionally memory-maps tensor data.
Parses the header, metadata, and tensor information from a GGUF file. If mmap is enabled, it will also memory-map the tensor data region. If mmap is disabled, tensor data pointers will be null and fd will be -1.
123 {
127 throw std::runtime_error(
"Failed to open file for metadata: " +
filename);
128 }
129
131
132
133
138
139 {
140 std::stringstream
ss;
141 ss <<
"Read Header:\n"
142 <<
" Magic: 0x" << std::hex <<
result.header.magic << std::dec <<
"\n"
143 <<
" Version: " <<
result.header.version <<
"\n"
144 <<
" Tensor Count: " <<
result.header.tensor_count <<
"\n"
145 <<
" Metadata KV Count: " <<
result.header.metadata_kv_count;
147 }
148
150 throw std::runtime_error("Not a valid GGUF file (magic number mismatch).");
151 }
152
154 std::to_string(
result.header.metadata_kv_count) +
" pairs)...");
156 std::string key;
158 try {
161
167 break;
168 }
173 break;
174 }
179 break;
180 }
185 break;
186 }
191 break;
192 }
197 break;
198 }
203 break;
204 }
208 result.metadata[key] = (
byte != 0);
209 break;
210 }
214 break;
215 }
220 break;
221 }
226 break;
227 }
232 break;
233 }
239
245 if (key == "tokenizer.ggml.tokens" &&
247 Logger::info(
"Loading STRING array data ('" + key +
"') with " +
248 std::to_string(
count) +
" elements...");
249 result.tokenizer_tokens.reserve(
static_cast<size_t>(
count));
252 }
254 std::to_string(
result.tokenizer_tokens.size()));
255 } else if (key == "tokenizer.ggml.scores" &&
257 Logger::info(
"Loading FLOAT32 array data ('" + key +
"') with " +
258 std::to_string(
count) +
" elements...");
259 result.tokenizer_scores.resize(
static_cast<size_t>(
count));
261 static_cast<std::streamsize
>(
count *
sizeof(
float)));
263 throw std::runtime_error(
264 "GGUF Error: Failed to read scores array data.");
265 }
267 std::to_string(
result.tokenizer_scores.size()));
268 } else if (key == "tokenizer.ggml.token_type" &&
271 " array data ('" + key + "') with " +
273 result.tokenizer_token_types.resize(
static_cast<size_t>(
count));
276 reinterpret_cast<char*
>(
result.tokenizer_token_types.data()),
278 } else {
285 }
286 }
288 throw std::runtime_error(
289 "GGUF Error: Failed to read token_type array data.");
290 }
292 std::to_string(
result.tokenizer_token_types.size()));
293 } else if (key == "tokenizer.ggml.merges" &&
295 Logger::info(
"Loading STRING array data ('" + key +
"') with " +
296 std::to_string(
count) +
" elements...");
297 result.tokenizer_merges.reserve(
static_cast<size_t>(
count));
300 }
302 std::to_string(
result.tokenizer_merges.size()));
303 } else {
306 "Skipping unhandled/non-tokenizer ARRAY data for key '" + key +
307 "' (Type: " +
309 ", Count: " + std::to_string(
count) +
")");
310
313 try {
315 }
catch (
const std::exception&
e) {
317 std::to_string(
arr_i) +
" for key '" + key +
319 throw;
320 }
321 }
322 } else {
325 throw std::runtime_error(
326 "Cannot skip array for key '" + key +
327 "' with unsupported or variable-sized element type: " +
329 }
330
333 throw std::overflow_error(
334 "Array size overflow calculating skip amount for key '" +
335 key + "'");
336 }
340 std::ios::cur);
342 throw std::runtime_error(
343 "GGUF Error: Failed to seek past array data for key '" +
344 key + "'");
345 }
346 }
347 }
348 }
349 break;
350 }
351 default: {
352 throw std::runtime_error(
353 "Unknown metadata type encountered: " +
355 " for key: " + key);
356 }
357 }
358 }
catch (
const std::exception&
e) {
360 key.empty() ? "(unknown key, error during key read)" : key;
362 "Error reading metadata for key: '" +
error_key +
365 throw;
366 }
367 }
369
370 result.tensor_infos.reserve(
static_cast<size_t>(
result.header.tensor_count));
372 std::to_string(
result.header.tensor_count) +
" tensors)...");
376 try {
378
382 throw std::runtime_error(
"Tensor '" + info.
name +
383 "' has unsupported number of dimensions: " +
385 }
389 }
390
394
396
398
401 <<
"[GGUF_TENSOR_INFO] Tensor " <<
i <<
" ('" << info.
name
402 <<
"'):" <<
"\n Raw offset from file: " << info.
offset
404 << "\n Calculated accumulated_offset_debug (before this tensor): "
406
411 throw std::overflow_error(
412 "Tensor dimension overflow calculating num_elements for tensor "
413 "'" +
415 }
417 }
418
421
423 throw std::runtime_error(
424 "Tensor '" + info.
name +
425 "' has unknown or unsupported type: " + std::to_string(info.
type));
426 }
427
430 throw std::runtime_error(
"Tensor '" + info.
name +
"' num_elements (" +
432 ") not divisible by block_size (" +
435 }
439 throw std::overflow_error(
440 "Tensor size overflow calculating size_in_bytes for tensor '" +
442 }
444 } else {
447 std::numeric_limits<uint64_t>::max() /
type_size) {
448 throw std::overflow_error(
449 "Tensor size overflow calculating size_in_bytes for tensor '" +
451 }
453 }
454
455 ss_offset_log <<
"\n Calculated size_in_bytes for this tensor: "
459
460 result.tensor_infos.push_back(info);
461 {
465 for (
size_t d = 0; d < info.
shape.size(); ++d)
467 << (d == info.
shape.size() - 1 ?
"" :
", ");
471 }
472 }
catch (
const std::exception&
e) {
474 info.
name.empty() ? (
"(unknown, index " + std::to_string(
i) +
")")
478 throw;
479 }
480 }
482
487 "'. Overwriting entry in map.");
488 }
490 }
491 Logger::info(
"Finished populating tensor_infos_map. Map size: " +
492 std::to_string(
result.tensor_infos_map.size()));
493
495 try {
496 if (
result.metadata.count(
"general.alignment")) {
498 std::get<uint32_t>(
result.metadata[
"general.alignment"]);
501 }
504 } else {
506 "Metadata key 'general.alignment' not found. Using default "
507 "alignment: " +
509 }
510 }
catch (
const std::bad_variant_access&
e) {
512 "Could not read 'general.alignment' metadata as uint32. Using default "
513 "alignment: " +
515 }
catch (
const std::exception&
e) {
517 std::string(
e.what()) +
518 ". Using default alignment: " + std::to_string(
alignment));
519 }
521
523 Logger::info(
"[GGUF_LOAD] Current file position (metadata stream) before padding seek: " +
527
530 "[GGUF_LOAD] Calculated actual_data_start_offset_in_file (for mmap): " +
532
535
537 Logger::info(
"[GGUF_LOAD] mmap is disabled by configuration. Loading tensor data into memory using OPTIMIZED bulk I/O.");
538
542 }
543
546
549 throw std::runtime_error(
"Failed to open file for tensor data reading: " +
filename);
550 }
551
554 throw std::runtime_error(
"Failed to seek to tensor data start in file: " +
filename);
555 }
556
557
561
563
566
569 throw std::runtime_error(
"Failed to read tensor data chunk at offset " + std::to_string(
bytes_read_total) +
" from file: " +
filename);
570 }
571
574
577 }
578 }
579
582
585 ss_bytes <<
"[GGUF_LOAD] First 16 bytes of tensor data: ";
586 for (
int i = 0;
i < 16; ++
i) {
587 ss_bytes <<
"0x" << std::hex << static_cast<int>(
result.tensor_data[
i]) <<
" ";
588 }
590 }
591 } else {
592 Logger::info(
"[GGUF_LOAD] No tensor data to load (total size is 0).");
593 }
594
596 }
597
598#ifndef _WIN32
600 if (
result.file_descriptor == -1) {
601 throw std::runtime_error(
"GGUF Error: Failed to open file for mmap: " +
filename +
" - " +
strerror(
errno));
602 }
603 Logger::info(
"[GGUF_LOAD] File opened for mmap with fd: " + std::to_string(
result.file_descriptor));
604
608 result.file_descriptor = -1;
609 throw std::runtime_error(
"GGUF Error: Failed to fstat file for mmap: " +
filename +
" - " +
strerror(
errno));
610 }
612#else
621 );
624 }
626
633 }
635#endif
636
638#ifndef _WIN32
640 result.file_descriptor = -1;
641#else
644#endif
645 throw std::runtime_error(
648 }
649
651 Logger::info(
"[GGUF_LOAD] Calculated tensor_data_block_size_on_disk (for mmap length calculation): " +
653
655#ifndef _WIN32
659 result.file_descriptor = -1;
660 throw std::runtime_error(std::string(
"GGUF Error: Failed to get page size using sysconf - ") +
strerror(
errno));
661 }
662#else
665
666
671 throw std::runtime_error("GGUF Error: Failed to get valid system allocation granularity (page_size equivalent for mmap offset).");
672 }
673#endif
674 Logger::info(
"[GGUF_LOAD] System page/allocation granularity for mmap offset: " + std::to_string(
page_size));
675
679
682 ", offset_diff_for_mmap=" + std::to_string(
result.offset_diff_for_mmap) +
684
687#ifndef _WIN32
691#else
696 0,
697 0,
699 );
705 }
706
707
708
711
717 result.mapped_tensor_data_size
718 );
719#endif
720
723#ifndef _WIN32
725
726#else
728
729#endif
730 result.mapped_tensor_data =
nullptr;
731 result.mapped_tensor_data_size = 0;
732 result.offset_diff_for_mmap = 0;
733 throw std::runtime_error(
"GGUF Error: mmap/MapViewOfFile failed. Aligned Offset: " + std::to_string(
mmap_offset) +
737#else
739#endif
740 }
741 Logger::info(
"[GGUF_LOAD] Successfully mmapped tensor data block. Mapped Address: " +
742 std::to_string(
reinterpret_cast<uintptr_t>(
result.mapped_tensor_data)) +
743 ", Mapped Size: " + std::to_string(
result.mapped_tensor_data_size) +
744 " bytes from file offset " + std::to_string(
mmap_offset));
745
746 if (
result.mapped_tensor_data_size >= (
result.offset_diff_for_mmap + 16)) {
748 ss_bytes <<
"[GGUF_LOAD] First 16 bytes of *actual* tensor data (after offset_diff) in mmap: ";
750 for (
int i = 0;
i < 16; ++
i)
753 }
754
755#ifndef _WIN32
756
757 Logger::info(
"[GGUF_LOAD] Attempting to prefetch mmapped tensor data using posix_madvise(MADV_WILLNEED)...");
759
761 Logger::error(
"[GGUF_LOAD] Invalid page_size for madvise alignment: " + std::to_string(
page_size) +
". Skipping prefetch.");
762 } else {
768
773
780 ") with error code " + std::to_string(
errno) +
781 " (" +
strerror(
errno) +
"). Skipping prefetch for this tensor.");
782 }
783 } else {
785 "' calculated region for madvise is invalid or out of overall mmap bounds. Skipping prefetch. "
786 );
787 }
788 }
789 }
790 }
791 Logger::info(
"[GGUF_LOAD] Finished POSIX prefetching attempt with posix_madvise.");
792
793#else
794 Logger::info(
"[GGUF_LOAD] Tensor prefetching (posix_madvise) is currently implemented for POSIX systems. Skipping for Windows for now.");
795#endif
796
797 } else {
798 Logger::info(
"[GGUF_LOAD] Tensor data block size (or mmap_length) is 0. Nothing to mmap.");
799 result.mapped_tensor_data =
nullptr;
800 result.mapped_tensor_data_size = 0;
801 result.offset_diff_for_mmap = 0;
802 }
803
804 Logger::info(
"GGUF metadata loaded and tensor data (if any) mmapped successfully.");
806}
static void warning(const std::string &message)
static void info(const std::string &message)
static void error(const std::string &message)
GGMLType
Enumeration of GGML tensor data types.
GGUFValueType
Enumeration of value types used in GGUF metadata.
size_t gguf_value_type_size(GGUFValueType type)
void read_raw(std::ifstream &file, T &dest)
Reads raw binary data from a file stream.
std::string read_gguf_string(std::ifstream &file)
Reads a string from a GGUF format file.
constexpr uint32_t GGUF_MAGIC
GGUF magic number that identifies the file format Spells "GGUF" in ASCII (0x47475546)
constexpr uint32_t GGUF_MAX_TENSOR_DIMS
constexpr uint64_t GGUF_DEFAULT_ALIGNMENT
Constants for GGUF file parsing and validation.
enum ember_ir::expr::@33::Value::Shape shape
size_t ggml_type_block_size(GGMLType type)
Gets the block size for a GGML type.
size_t ggml_type_size(GGMLType type)
Gets the size in bytes of a GGML type.
const char * ggml_type_name(GGMLType type)
Gets the string name of a GGML type.
Represents an array in GGUF metadata.
Complete representation of a GGUF file's contents.
static const void * MMapFailure
Information about a tensor stored in a GGUF file.
std::vector< uint64_t > shape