From: Guilherme Quintino Date: Tue, 4 Aug 2026 18:27:47 +0000 (+0100) Subject: gguf-split: Add option to delete split parts during merge (#26538) X-Git-Tag: upstream/0.0.10438~166 X-Git-Url: https://git.djapps.eu/?a=commitdiff_plain;h=76c956c1372962842e1134f86b7c5d4517597e7e;p=pkg%2Fggml%2Fsources%2Fllama.cpp gguf-split: Add option to delete split parts during merge (#26538) * Add delete-files option to split parameters Added a new option to delete split files during execution to free up disk space. * Add test for delete files on merge option * Fix tests * Update tools/gguf-split/gguf-split.cpp Co-authored-by: Sigbjørn Skjæret * Update tools/gguf-split/gguf-split.cpp Co-authored-by: Sigbjørn Skjæret * Uncomment tests * Improvements to address PR comments * Fix formatting * Fix formatting * Rename --delete-files to --delete-splits * Comment tests * Move delete inside loop * style cleanup --------- Co-authored-by: Sigbjørn Skjæret --- diff --git a/tools/gguf-split/gguf-split.cpp b/tools/gguf-split/gguf-split.cpp index 8a6b5c198..5cafcc9aa 100644 --- a/tools/gguf-split/gguf-split.cpp +++ b/tools/gguf-split/gguf-split.cpp @@ -47,6 +47,7 @@ struct split_params { std::string output; bool no_tensor_first_split = false; bool dry_run = false; + bool delete_splits = false; }; static void split_print_usage(const char * executable) { @@ -65,6 +66,7 @@ static void split_print_usage(const char * executable) { printf(" --split-max-size N(M|G) max size per split\n"); printf(" --no-tensor-first-split do not add tensors to the first split (disabled by default)\n"); printf(" --dry-run only print out a split plan and exit, without writing any new files\n"); + printf(" --delete-splits delete the split files during merge to free up disk space WARNING: this option is unsafe and will leave you in an unrecoverable state if something fails during the merge\n"); printf("\n"); } @@ -147,6 +149,9 @@ static void split_params_parse_ex(int argc, const char ** argv, split_params & p } params.mode = MODE_SIZE; params.n_bytes_split = split_str_to_n_bytes(argv[arg_idx]); + } else if (arg == "--delete-splits") { + arg_found = true; + params.delete_splits = true; } if (!arg_found) { @@ -509,6 +514,7 @@ static void gguf_merge(const split_params & split_params) { } // Write tensors data + bool merge_error = false; for (int i_split = 0; i_split < n_split; i_split++) { llama_split_path(split_path, sizeof(split_path), split_prefix, i_split, n_split); std::ifstream f_input(split_path, std::ios::binary); @@ -554,6 +560,16 @@ static void gguf_merge(const split_params & split_params) { ggml_free(ctx_meta); f_input.close(); fprintf(stderr, "\033[3Ddone\n"); + + if (!split_params.dry_run && split_params.delete_splits) { + int delete_result = std::remove(split_path); + if (delete_result != 0) { + merge_error = true; + fprintf(stderr, "error: failed to delete %s\n", split_path); + } else { + fprintf(stderr, "%s: deleted file %s\n", __func__, split_path); + } + } } if (!split_params.dry_run) { @@ -568,6 +584,10 @@ static void gguf_merge(const split_params & split_params) { fprintf(stderr, "%s: %s merged from %d split with %d tensors.\n", __func__, split_params.output.c_str(), n_split, total_tensors); + + if (merge_error) { + exit(EXIT_FAILURE); + } } int main(int argc, const char ** argv) { diff --git a/tools/gguf-split/tests.sh b/tools/gguf-split/tests.sh index c8dd0b007..dcd66681b 100755 --- a/tools/gguf-split/tests.sh +++ b/tools/gguf-split/tests.sh @@ -66,12 +66,12 @@ echo PASS echo # 5. Merge -#$SPLIT --merge $WORK_PATH/ggml-model-split-32-tensors-00001-of-00012.gguf $WORK_PATH/ggml-model-merge-2.gguf +#$SPLIT --merge $WORK_PATH/ggml-model-split-32-tensors-00001-of-00011.gguf $WORK_PATH/ggml-model-merge-2.gguf #echo PASS #echo # 5b. Test the merged model is loading properly -#$MAIN -no-cnv --model $WORK_PATH/ggml-model-merge-2.gguf --n-predict 32 +#$MAIN -no-cnv --model $WORK_PATH/ggml-model-merge-2.gguf -p "I believe the meaning of life is" --n-predict 32 #echo PASS #echo @@ -85,5 +85,25 @@ $MAIN -no-cnv --model $WORK_PATH/ggml-model-split-500M-00001-of-00002.gguf -p "I echo PASS echo +# 7. Merge with delete splits +#for i in $(seq -w 1 11); do +# cp "$WORK_PATH/ggml-model-split-32-tensors-000${i}-of-00011.gguf" "$WORK_PATH/ggml-model-split-32-tensors-copy-000${i}-of-00011.gguf" +#done +#$SPLIT --merge --delete-splits $WORK_PATH/ggml-model-split-32-tensors-copy-00001-of-00011.gguf $WORK_PATH/ggml-model-merge-3.gguf +#echo PASS +#echo + +# 7b. Test the merged model is loading properly +#$MAIN -no-cnv --model $WORK_PATH/ggml-model-merge-3.gguf -p "I believe the meaning of life is" --n-predict 32 +#echo PASS +#echo + +# 7c. Test the files were deleted +#for i in $(seq -w 1 11); do +# test ! -f "$WORK_PATH/ggml-model-split-32-tensors-copy-000${i}-of-00011.gguf" +#done +#echo PASS +#echo + # Clean up rm -f $WORK_PATH/ggml-model-split*.gguf $WORK_PATH/ggml-model-merge*.gguf