Skip to content

Commit a5be6c1

Browse files
committed
[common] GGUF reader from memory
Add new GGUF reader implementation that can read metadata from a memory buffer.
1 parent 3a5b2ca commit a5be6c1

File tree

2 files changed

+95
-13
lines changed

2 files changed

+95
-13
lines changed

ggml/include/gguf.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ extern "C" {
7878

7979
GGML_API struct gguf_context * gguf_init_empty(void);
8080
GGML_API struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_params params);
81-
//GGML_API struct gguf_context * gguf_init_from_buffer(..);
8281

8382
GGML_API void gguf_free(struct gguf_context * ctx);
8483

@@ -200,3 +199,8 @@ extern "C" {
200199
#ifdef __cplusplus
201200
}
202201
#endif
202+
203+
#ifdef __cplusplus
204+
#include <ios>
205+
GGML_API struct gguf_context * gguf_init_from_buffer(std::basic_streambuf<uint8_t>& streambuf, struct gguf_init_params params);
206+
#endif

ggml/src/gguf.cpp

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "ggml-backend.h"
33
#include "ggml-impl.h"
44
#include "gguf.h"
5+
#include "uint8-buff-stream.h"
56

67
#include <cinttypes>
78
#include <cstddef>
@@ -216,14 +217,79 @@ struct gguf_context {
216217
void * data = nullptr;
217218
};
218219

219-
struct gguf_reader {
220+
struct gguf_bytes_reader {
221+
/// @brief Reads up to `count` objects into the array `buffer`.
222+
/// The position of the underlying stream implementation is advanced
223+
/// by the number of characters read.
224+
///
225+
/// @note If an error occurs, the resulting value of the underlying stream
226+
/// position indicator is indeterminate.
227+
virtual size_t read(void * buffer, size_t size, size_t count) = 0;
228+
229+
/// @brief Seeks to a position aligned to the given alignment boundary.
230+
/// @return The current position after alignment, or 0 on error.
231+
virtual size_t align(size_t alignment) = 0;
232+
233+
virtual ~gguf_bytes_reader() = 0;
234+
};
235+
236+
gguf_bytes_reader::~gguf_bytes_reader() {}
237+
238+
struct gguf_bytes_buffer_reader : public gguf_bytes_reader {
239+
gguf_bytes_buffer_reader(std::basic_streambuf<uint8_t> & streambuf) : streambuf(streambuf), offset(0) {}
240+
241+
~gguf_bytes_buffer_reader() {}
242+
243+
size_t read(void * buffer, size_t size, size_t count) override {
244+
size_t total_size = size * count;
245+
auto bytes_read = streambuf.sgetn(static_cast<uint8_t *>(buffer), total_size);
246+
offset += bytes_read;
247+
return bytes_read;
248+
}
249+
250+
size_t align(size_t alignment) override {
251+
size_t new_offset = GGML_PAD(offset, alignment);
252+
size_t seek_offset = new_offset - offset;
253+
254+
auto result = streambuf.pubseekoff(seek_offset, std::ios_base::cur);
255+
if (result == std::streampos(-1)) {
256+
return 0;
257+
}
258+
offset = new_offset;
259+
return offset;
260+
}
261+
262+
private:
263+
std::basic_streambuf<uint8_t> & streambuf;
264+
size_t offset;
265+
};
266+
267+
struct gguf_bytes_file_reader : public gguf_bytes_reader {
268+
gguf_bytes_file_reader(FILE * file) : file(file) {}
269+
270+
~gguf_bytes_file_reader() {}
271+
272+
size_t read(void * buffer, size_t size, size_t count) override { return fread(buffer, 1, size * count, file); }
273+
274+
size_t align(size_t alignment) override {
275+
if (fseek(file, GGML_PAD(ftell(file), alignment), SEEK_SET) != 0) {
276+
return 0;
277+
}
278+
return ftell(file);
279+
}
280+
281+
private:
220282
FILE * file;
283+
};
221284

222-
gguf_reader(FILE * file) : file(file) {}
285+
struct gguf_reader {
286+
gguf_bytes_reader& bytes_reader;
287+
288+
gguf_reader(gguf_bytes_reader& bytes_reader) : bytes_reader(bytes_reader) {}
223289

224290
template <typename T>
225291
bool read(T & dst) const {
226-
return fread(&dst, 1, sizeof(dst), file) == sizeof(dst);
292+
return bytes_reader.read(&dst, 1, sizeof(dst)) == sizeof(dst);
227293
}
228294

229295
template <typename T>
@@ -278,11 +344,11 @@ struct gguf_reader {
278344
return false;
279345
}
280346
dst.resize(size);
281-
return fread(dst.data(), 1, dst.length(), file) == dst.length();
347+
return bytes_reader.read(dst.data(), 1, dst.length()) == dst.length();
282348
}
283349

284350
bool read(void * dst, const size_t size) const {
285-
return fread(dst, 1, size, file) == size;
351+
return bytes_reader.read(dst, 1, size) == size;
286352
}
287353
};
288354

@@ -316,8 +382,8 @@ bool gguf_read_emplace_helper(const struct gguf_reader & gr, std::vector<struct
316382
return true;
317383
}
318384

319-
struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_params params) {
320-
const struct gguf_reader gr(file);
385+
namespace {
386+
struct gguf_context * gguf_init_from_reader_impl(const struct gguf_reader& gr, struct gguf_init_params params) {
321387
struct gguf_context * ctx = new gguf_context;
322388

323389
bool ok = true;
@@ -606,15 +672,14 @@ struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_par
606672
GGML_ASSERT(int64_t(ctx->info.size()) == n_tensors);
607673

608674
// we require the data section to be aligned, so take into account any padding
609-
if (fseek(file, GGML_PAD(ftell(file), ctx->alignment), SEEK_SET) != 0) {
610-
GGML_LOG_ERROR("%s: failed to seek to beginning of data section\n", __func__);
675+
// store the current file offset - this is where the data section starts
676+
ctx->offset = gr.bytes_reader.align(ctx->alignment);
677+
if (ctx->offset == 0) {
678+
GGML_LOG_ERROR("%s: failed to align data section\n", __func__);
611679
gguf_free(ctx);
612680
return nullptr;
613681
}
614682

615-
// store the current file offset - this is where the data section starts
616-
ctx->offset = ftell(file);
617-
618683
// compute the total size of the data section, taking into account the alignment
619684
{
620685
ctx->size = 0;
@@ -718,6 +783,13 @@ struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_par
718783

719784
return ctx;
720785
}
786+
}
787+
788+
struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_params params) {
789+
gguf_bytes_file_reader bytes_reader(file);
790+
gguf_reader reader(bytes_reader);
791+
return gguf_init_from_reader_impl(reader, params);
792+
}
721793

722794
struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_params params) {
723795
FILE * file = ggml_fopen(fname, "rb");
@@ -732,6 +804,12 @@ struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_p
732804
return result;
733805
}
734806

807+
struct gguf_context * gguf_init_from_buffer(std::basic_streambuf<uint8_t> & streambuf, struct gguf_init_params params) {
808+
gguf_bytes_buffer_reader bytes_reader(streambuf);
809+
gguf_reader reader(bytes_reader);
810+
return gguf_init_from_reader_impl(reader, params);
811+
}
812+
735813
void gguf_free(struct gguf_context * ctx) {
736814
if (ctx == nullptr) {
737815
return;

0 commit comments

Comments
 (0)