]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
gguf-split: Add option to delete split parts during merge (#26538)
authorGuilherme Quintino <redacted>
Tue, 4 Aug 2026 18:27:47 +0000 (19:27 +0100)
committerGitHub <redacted>
Tue, 4 Aug 2026 18:27:47 +0000 (21:27 +0300)
* 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 <redacted>
* Update tools/gguf-split/gguf-split.cpp

Co-authored-by: Sigbjørn Skjæret <redacted>
* 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 <redacted>
tools/gguf-split/gguf-split.cpp
tools/gguf-split/tests.sh

index 8a6b5c198b217ab858b65f1b680b945ef62e554b..5cafcc9aa96afa4762785f8d00eb9b8d5c7b2601 100644 (file)
@@ -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) {
index c8dd0b0079530d52dca1ea69b987ea5204e21ce9..dcd66681bb83d9871ed825836b3885477afc1305 100755 (executable)
@@ -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