GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 23 / 0 / 23
Functions: 100.0% 12 / 0 / 12
Branches: -% 0 / 0 / 0

include/brotensor/gguf.h
Line Branch Exec Source
1 #pragma once
2
3 // GGUF reader for brotensor. Chunk 1 — loader + storage carrier only; no
4 // dequant kernels and no ops dispatch on quant dtypes.
5 //
6 // Format spec: https://github.com/ggerganov/ggml/blob/master/docs/gguf.md
7 //
8 // The file is mmap'd; TensorInfo::data points directly into the mapping, so
9 // it's valid only while the owning File is alive. Zero-copy on the read path.
10 // brotensor is 2D-only — gguf::shape_to_2d() collapses the GGUF
11 // (innermost-first) dim list to (rows, cols) for upload_raw().
12
13 #include <brotensor/tensor.h>
14 #include <brotensor/detail/string_hash.h>
15
16 #include <cstddef>
17 #include <cstdint>
18 #include <functional>
19 #include <string>
20 #include <string_view>
21 #include <unordered_map>
22 #include <utility>
23 #include <vector>
24
25 namespace brotensor::gguf {
26
27 enum class ValueType : uint32_t {
28 U8 = 0, I8 = 1, U16 = 2, I16 = 3, U32 = 4, I32 = 5,
29 F32 = 6, Bool = 7, String = 8, Array = 9,
30 U64 = 10, I64 = 11, F64 = 12,
31 };
32
33 190 struct Value {
34 95 ValueType type = ValueType::U32;
35 // Only the field matching `type` (or, for arrays, `array_elem_type` on
36 // each element) is meaningful.
37 union Scalar {
38 uint8_t u8; int8_t i8;
39 uint16_t u16; int16_t i16;
40 uint32_t u32; int32_t i32;
41 uint64_t u64; int64_t i64;
42 float f32; double f64;
43 bool b;
44 95 } scalar{};
45 std::string str;
46 95 ValueType array_elem_type = ValueType::U32;
47 std::vector<Value> array;
48 };
49
50 83 struct TensorInfo {
51 std::string name;
52 // Dim order is innermost-first, as stored on disk. shape_to_2d() returns
53 // (rows = product(shape[1..]), cols = shape[0]).
54 std::vector<int64_t> shape;
55 83 uint32_t ggml_type = 0;
56 83 brotensor::Dtype dtype = brotensor::Dtype::FP32;
57 83 bool dtype_supported = true;
58 83 const uint8_t* data = nullptr;
59 83 std::size_t nbytes = 0;
60 83 int64_t numel = 1;
61 };
62
63 class File {
64 public:
65 78 File() = default;
66 ~File();
67
68 File(File&& other) noexcept;
69 File& operator=(File&& other) noexcept;
70 File(const File&) = delete;
71 File& operator=(const File&) = delete;
72
73 static File open(const std::string& path);
74
75 const TensorInfo* find_tensor(std::string_view name) const;
76 const TensorInfo& get_tensor(std::string_view name) const;
77 1 const std::vector<TensorInfo>& tensors() const { return tensors_; }
78
79 const Value* find_meta(std::string_view key) const;
80 const Value& get_meta(std::string_view key) const;
81 1 const std::vector<std::pair<std::string, Value>>& metadata() const { return metadata_; }
82
83 5 uint32_t version() const { return version_; }
84 6 uint32_t alignment() const { return alignment_; }
85 9 std::size_t tensor_count() const { return tensors_.size(); }
86
87 private:
88 void release_() noexcept;
89
90 26 void* file_ = nullptr;
91 26 void* mapping_ = nullptr;
92 26 void* base_ = nullptr;
93 26 std::size_t file_size_ = 0;
94
95 26 uint32_t version_ = 0;
96 26 uint32_t alignment_ = 32;
97
98 std::vector<std::pair<std::string, Value>> metadata_;
99 std::unordered_map<std::string, std::size_t, detail::StringHash, std::equal_to<>> meta_index_;
100 std::vector<TensorInfo> tensors_;
101 std::unordered_map<std::string, std::size_t, detail::StringHash, std::equal_to<>> tensor_index_;
102 };
103
104 // Convert GGUF shape (innermost-first) to brotensor 2D (rows, cols). cols is
105 // the innermost (contiguous) axis; rows is the product of the remaining axes.
106 // 1D input → (shape[0], 1). Empty shape throws.
107 std::pair<int, int> shape_to_2d(const std::vector<int64_t>& shape);
108
109 // Allocate `dst` on the current default device sized for `info.numel`
110 // elements at `info.dtype` (via dtype_storage_bytes) and copy info.nbytes
111 // bytes from the mmap into it. For quant dtypes, cols must be a multiple of
112 // dtype_block_size(dtype) (blocks run along the contiguous axis). Throws if
113 // info.dtype_supported is false or rows*cols != info.numel.
114 void upload_raw(const TensorInfo& info, int rows, int cols,
115 brotensor::Tensor& dst);
116
117 } // namespace brotensor::gguf
118