diff --git a/include/llama.h b/include/llama.h index f05e9bd247..df2ab4ab4b 100644 --- a/include/llama.h +++ b/include/llama.h @@ -464,9 +464,8 @@ extern "C" { const char * path_model, struct llama_model_params params); - // Load a model from a POSIX file descriptor - // Not supported on Windows - LLAMA_API struct llama_model * llama_model_load_from_fd(int fd, struct llama_model_params params); + // Load a model from an open FILE pointer + LLAMA_API struct llama_model * llama_model_load_from_file_ptr(FILE * file, struct llama_model_params params); // Load a model from multiple splits (support custom naming scheme) // The paths must be in the correct order diff --git a/src/llama-model-loader.cpp b/src/llama-model-loader.cpp index 358b505f18..6af0ee1fe5 100644 --- a/src/llama-model-loader.cpp +++ b/src/llama-model-loader.cpp @@ -13,10 +13,6 @@ #include #include -#ifndef _WIN32 -#include -#endif // _WIN32 - static const size_t kiB = 1024; static const size_t MiB = 1024*kiB; static const size_t GiB = 1024*MiB; @@ -514,7 +510,7 @@ llama_model_loader::llama_model_loader( void * set_tensor_data_ud, const std::string & fname, std::vector & splits, - int fd, + FILE * file, bool use_mmap, bool use_direct_io, bool check_tensors, @@ -662,35 +658,23 @@ llama_model_loader::llama_model_loader( LLAMA_LOG_INFO("%s: additional %d GGUFs metadata loaded.\n", __func__, n_split - 1); } - } else if (fd >= 0) { - const int fd_duped = dup(fd); - if (fd_duped < 0) { - throw std::runtime_error(format("%s: failed to dup fd %d: %s", __func__, fd, strerror(errno))); - } - - FILE * f = fdopen(fd_duped, "rb"); - if (!f) { - close(fd_duped); - throw std::runtime_error(format("%s: failed to fdopen fd %d: %s", __func__, fd, strerror(errno))); - } - + } else if (file) { struct ggml_context * ctx = NULL; struct gguf_init_params params = { /*.no_alloc = */ true, /*.ctx = */ &ctx, }; - metadata_ptr.reset(gguf_init_from_file_ptr(f, params)); - fclose(f); + metadata_ptr.reset(gguf_init_from_file_ptr(file, params)); metadata = metadata_ptr.get(); if (metadata == nullptr) { - throw std::runtime_error(format("%s: failed to load model from fd %d", __func__, fd)); + throw std::runtime_error(format("%s: failed to load model from file pointer", __func__)); } get_key(llm_kv(LLM_KV_GENERAL_ARCHITECTURE), arch_name, false); llm_kv = LLM_KV(llm_arch_from_string(arch_name)); - files.emplace_back(new llama_file(fd)); + files.emplace_back(new llama_file(fileno(file))); contexts.emplace_back(ctx); // Save tensors data offset info of the main file. @@ -715,7 +699,7 @@ llama_model_loader::llama_model_loader( fver = (enum llama_fver) gguf_get_version(metadata); LLAMA_LOG_INFO("%s: loaded meta data with %d key-value pairs and %d tensors from %s (version %s)\n", - __func__, n_kv, n_tensors, fname.empty() ? "(fd)" : fname.c_str(), llama_file_version_name(fver)); + __func__, n_kv, n_tensors, fname.empty() ? "(file*)" : fname.c_str(), llama_file_version_name(fver)); // determine file type based on the number of tensors for each quantization and print meta data // TODO: make optional diff --git a/src/llama-model-loader.h b/src/llama-model-loader.h index 6e5a5a4712..7b3d6703c0 100644 --- a/src/llama-model-loader.h +++ b/src/llama-model-loader.h @@ -125,7 +125,7 @@ struct llama_model_loader { void * set_tensor_data_ud, const std::string & fname, std::vector & splits, // optional, only need if the split does not follow naming scheme - int fd, + FILE * file, bool use_mmap, bool use_direct_io, bool check_tensors, diff --git a/src/llama-quant.cpp b/src/llama-quant.cpp index d047944dd6..c414656e0a 100644 --- a/src/llama-quant.cpp +++ b/src/llama-quant.cpp @@ -859,7 +859,7 @@ static void llama_model_quantize_impl(const std::string & fname_inp, const std:: std::vector splits = {}; llama_model_loader ml(/*metadata*/ nullptr, /*set_tensor_data*/ nullptr, /*set_tensor_data_ud*/ nullptr, - fname_inp, splits, /*fd*/ -1, use_mmap, /*use_direct_io*/ false, /*check_tensors*/ true, /*no_alloc*/ false, kv_overrides, nullptr); + fname_inp, splits, /*file*/ nullptr, use_mmap, /*use_direct_io*/ false, /*check_tensors*/ true, /*no_alloc*/ false, kv_overrides, nullptr); ml.init_mappings(false); // no prefetching llama_model model(llama_model_default_params()); diff --git a/src/llama.cpp b/src/llama.cpp index c40d5c9d51..d35fb2cbe6 100644 --- a/src/llama.cpp +++ b/src/llama.cpp @@ -828,7 +828,7 @@ int64_t llama_time_us(void) { // Returns 0 on success, -1 on error, and -2 on cancellation via llama_progress_callback static int llama_model_load(struct gguf_context * metadata, llama_model_set_tensor_data_t set_tensor_data, void * set_tensor_data_ud, - const std::string & fname, std::vector & splits, int fd, llama_model & model, llama_model_params & params) { + const std::string & fname, std::vector & splits, FILE * file, llama_model & model, llama_model_params & params) { // loading time will be recalculated after the first eval, so // we take page faults deferred by mmap() into consideration model.t_load_us = 0; @@ -837,7 +837,7 @@ static int llama_model_load(struct gguf_context * metadata, llama_model_set_tens model.t_start_us = tm.t_start_us; try { - llama_model_loader ml(metadata, set_tensor_data, set_tensor_data_ud, fname, splits, fd, params.use_mmap, params.use_direct_io, + llama_model_loader ml(metadata, set_tensor_data, set_tensor_data_ud, fname, splits, file, params.use_mmap, params.use_direct_io, params.check_tensors, params.no_alloc, params.kv_overrides, params.tensor_buft_overrides); ml.print_info(); @@ -889,9 +889,9 @@ static struct llama_model * llama_model_load_from_file_impl( void * set_tensor_data_ud, const std::string & path_model, std::vector & splits, - int fd, + FILE * file, struct llama_model_params params) { - if (metadata == nullptr && path_model.empty() && fd < 0) { + if (metadata == nullptr && path_model.empty() && !file) { LLAMA_LOG_ERROR("%s: no model source provided\n", __func__); return nullptr; } @@ -1015,7 +1015,7 @@ static struct llama_model * llama_model_load_from_file_impl( props.memory_free/1024/1024); } - const int status = llama_model_load(metadata, set_tensor_data, set_tensor_data_ud, path_model, splits, fd, *model, params); + const int status = llama_model_load(metadata, set_tensor_data, set_tensor_data_ud, path_model, splits, file, *model, params); GGML_ASSERT(status <= 0); if (status < 0) { if (status == -1) { @@ -1041,7 +1041,7 @@ struct llama_model * llama_model_init_from_user( std::vector splits = {}; params.use_mmap = false; params.use_extra_bufts = false; - return llama_model_load_from_file_impl(metadata, set_tensor_data, set_tensor_data_ud, path_model, splits, /*fd*/ -1, params); + return llama_model_load_from_file_impl(metadata, set_tensor_data, set_tensor_data_ud, path_model, splits, /*file*/ nullptr, params); } // deprecated struct llama_model * llama_load_model_from_file( @@ -1054,7 +1054,7 @@ struct llama_model * llama_model_load_from_file( const char * path_model, struct llama_model_params params) { std::vector splits = {}; - return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, path_model, splits, /*fd*/ -1, params); + return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, path_model, splits, /*file*/ nullptr, params); } struct llama_model * llama_model_load_from_splits( @@ -1070,20 +1070,17 @@ struct llama_model * llama_model_load_from_splits( for (size_t i = 0; i < n_paths; ++i) { splits.push_back(paths[i]); } - return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, splits.front(), splits, /*fd*/ -1, params); + return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, splits.front(), splits, /*file*/ nullptr, params); } -struct llama_model * llama_model_load_from_fd(int fd, struct llama_model_params params) { -#ifdef _WIN32 - LLAMA_LOG_ERROR("%s: fd-based loading is not supported on Windows\n", __func__); - GGML_UNUSED(fd); - GGML_UNUSED(params); - return nullptr; -#else +struct llama_model * llama_model_load_from_file_ptr(FILE * file, struct llama_model_params params) { + if (!file) { + LLAMA_LOG_ERROR("%s: file is NULL\n", __func__); + return nullptr; + } std::string path_model; std::vector splits = {}; - return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, path_model, splits, fd, params); -#endif // _WIN32 + return llama_model_load_from_file_impl(nullptr, nullptr, nullptr, path_model, splits, file, params); } void llama_model_save_to_file(const struct llama_model * model, const char * path_model) { diff --git a/tests/test-model-load-fd.cpp b/tests/test-model-load-fd.cpp index dd982ba907..b7ff237ee5 100644 --- a/tests/test-model-load-fd.cpp +++ b/tests/test-model-load-fd.cpp @@ -24,20 +24,27 @@ int main(int argc, char ** argv) { return EXIT_FAILURE; } + FILE * f = fdopen(dup(fd), "rb"); + close(fd); + if (!f) { + fprintf(stderr, "failed to fdopen\n"); + return EXIT_FAILURE; + } + auto params = llama_model_default_params(); params.use_mmap = true; params.vocab_only = true; - struct llama_model * model = llama_model_load_from_fd(fd, params); - close(fd); + struct llama_model * model = llama_model_load_from_file_ptr(f, params); + fclose(f); if (model == nullptr) { - fprintf(stderr, "load from fd failed\n"); + fprintf(stderr, "load from file pointer failed\n"); return EXIT_FAILURE; } const int n_vocab = llama_vocab_n_tokens(llama_model_get_vocab(model)); - fprintf(stderr, "loaded %d tokens from fd\n", n_vocab); + fprintf(stderr, "loaded %d tokens via file pointer\n", n_vocab); llama_model_free(model); llama_backend_free();