Skip to content

fix(build): add missing link recipes for llama-bench, quantize, imatrix and perplexity - #1034

Open
dexhunter wants to merge 1 commit into
mozilla-ai:mainfrom
dexhunter:fix/link-recipes-for-llama-cpp-tools
Open

fix(build): add missing link recipes for llama-bench, quantize, imatrix and perplexity#1034
dexhunter wants to merge 1 commit into
mozilla-ai:mainfrom
dexhunter:fix/link-recipes-for-llama-cpp-tools

Conversation

@dexhunter

Copy link
Copy Markdown

Description

o/$(MODE)/llama.cpp lists five executables, but only llama-server is ever
built. llama-bench, quantize, imatrix and perplexity are silently never
linked: make compiles their objects, reports success and exits 0, and no
binary is produced.

Two things are missing in llama.cpp.patches/llamafile-files/BUILD.mk:

1. No link recipe. Each of the four tools declares prerequisites but has no
recipe:

o/$(MODE)/llama.cpp/llama-bench/llama-bench: \
	$(TOOL_BENCH_OBJS) \
	$$(TINYBLAS_CPU_OBJS) \
	o/$(MODE)/llama.cpp/llama.cpp.a

A prerequisite-only rule adds dependencies; it does not build anything. The
generic link rule in build/rules.mk (o/$(MODE)/%: o/$(MODE)/%.o) cannot fill
the gap either, because the paths do not line up — the target is
o/$(MODE)/llama.cpp/llama-bench/llama-bench, so the pattern looks for
o/$(MODE)/llama.cpp/llama-bench/llama-bench.o, while the object that exists is
o/$(MODE)/llama.cpp/tools/llama-bench/llama-bench.cpp.o. With no recipe and no
matching pattern rule, make treats the target as already satisfied and prints
Nothing to be done — so a missing binary looks exactly like a successful
build.

2. main() is not compiled in. Upstream splits three of these tools into a
reusable implementation file plus a small main.cpp. Only the implementation
file was listed:

tool file with main() was in *_SRCS?
llama-bench tools/llama-bench/main.cpp no
quantize tools/quantize/main.cpp no
perplexity tools/perplexity/main.cpp no
imatrix tools/imatrix/imatrix.cpp yes

So even with a recipe added, three of the four would fail to link with
undefined reference to main.

This has been the case since the v0.10.0 rewrite (4cc1a5f7, "llamafile
reloaded", #867), which gave llama-server a recipe but not the other four.

What this PR changes

One file, llama.cpp.patches/llamafile-files/BUILD.mk:

  1. Adds main.cpp to TOOL_BENCH_SRCS, TOOL_QUANTIZE_SRCS and
    TOOL_PERPLEXITY_SRCS.
  2. Adds a link recipe to each of the four tools, in the project's generic link
    form ($(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@, the same shape as the
    generic rule in build/rules.mk), preceded by @mkdir -p $(dir $@) as
    llama-server does.

The tools take the same support objects as llama-server minus the server-only
ones, because llama.cpp.a itself references them:

  • $(TOOL_LLAMAFILE_OBJS)src/llama-mmap.cpp and ggml/src/gguf.cpp are
    patched to call llamafile_open_gguf(), llamafile_read(),
    llamafile_ref(), …
  • $(HTTPLIB_OBJS) + o/$(MODE)/third_party/mbedtls/mbedtls.a
    common/download.cpp, common/hf-cache.cpp and common/license.cpp are
    compiled with -DLLAMA_USE_HTTPLIB.

No other build logic is touched, and nothing outside this file changes.

PR Type

  • 🐛 Bug Fix

Relevant issues

No issue is fixed by this PR. Context: llama-bench is the standard reproducer
for the dense-model CPU performance gap being investigated in #980, and it
cannot currently be built from this repository — so this change is a
prerequisite for reproducing that comparison with llamafile's own build rather
than an upstream one. It does not address the performance gap itself.

Verification

All commands run on Linux x86-64 from a clean clone at
0ce2b877b22346ac11315425daf47448f73f3283 (Update llama.cpp to b10103 (c588c4f) (#1030)), with make setup (llama.cpp submodule at
c588c4f47683e73ad2d69f50480bec6cc85fd0f7, b10103) and .cosmocc/4.0.2/bin/make.

Before — build succeeds, binaries are absent:

$ .cosmocc/4.0.2/bin/make -j o//llama.cpp
$ echo $?
0
MISSING  o//llama.cpp/llama-bench/llama-bench
MISSING  o//llama.cpp/quantize/quantize
MISSING  o//llama.cpp/imatrix/imatrix
MISSING  o//llama.cpp/perplexity/perplexity
PRESENT  o//llama.cpp/server/llama-server  32958357 bytes

$ .cosmocc/4.0.2/bin/make o//llama.cpp/llama-bench/llama-bench
make: Nothing to be done for 'o//llama.cpp/llama-bench/llama-bench'.
$ echo $?
0

The same Nothing to be done / exit 0 result holds for quantize, imatrix
and perplexity.

After — all five build:

PRESENT  o//llama.cpp/llama-bench/llama-bench   15601565 bytes
PRESENT  o//llama.cpp/quantize/quantize         11906312 bytes
PRESENT  o//llama.cpp/imatrix/imatrix           19959204 bytes
PRESENT  o//llama.cpp/perplexity/perplexity     19960937 bytes
PRESENT  o//llama.cpp/server/llama-server       32958357 bytes

Each new binary runs:

$ ./o//llama.cpp/llama-bench/llama-bench --help    # exit 0, 63 lines of usage
$ ./o//llama.cpp/quantize/quantize --help          # exit 1 (upstream usage() calls exit(1)), 89 lines
$ ./o//llama.cpp/imatrix/imatrix --help            # exit 0, 320 lines
$ ./o//llama.cpp/perplexity/perplexity --help      # exit 0, 323 lines
$ ./o//llama.cpp/imatrix/imatrix --version
version: 1784965889 (c588c4f47)
built with cosmocc for cosmopolitan

quantize also reaches the real quantization path rather than just printing
usage:

$ ./o//llama.cpp/quantize/quantize /nonexistent-model.gguf Q4_0
gguf_init_from_file: failed to open GGUF file '/nonexistent-model.gguf': No such file or directory
llama_model_quantize: failed to quantize: llama_model_loader: failed to load model from /nonexistent-model.gguf
llama_quantize: failed to quantize model from '/nonexistent-model.gguf'

llama-server is unaffected. Editing BUILD.mk invalidates every object
that depends on it, so the server was fully recompiled (242 translation units)
and relinked from the patched makefile. The resulting binary is byte-for-byte
identical to the one built before the change:

a56f78e880db47e527a3928baf881b4cf7fc25b6c2eada40ae8a70b963d499e7  (before)
a56f78e880db47e527a3928baf881b4cf7fc25b6c2eada40ae8a70b963d499e7  (after)

(This comparison is an incremental rebuild in the same tree on purpose.
LLAMA_BUILD_NUMBER := $(shell date +%s) bakes a wall-clock timestamp into
build-info.cpp, so binaries are not reproducible across a from-scratch
rebuild; build-info.cpp depends only on build-info.cpp.in, so keeping it
fixed across the incremental rebuild is what makes the comparison isolate the
effect of the BUILD.mk change.)

Test suite.cosmocc/4.0.2/bin/make check exits 0:

extract_data_uris_test:  all 19 tests PASSED
fa_helpers_test:         9 tests registered; all 3 assertions PASSED
                         (73 skipped — this CPU lacks the optimized variant)
gpu_backend_test:        all 23 checks PASSED
sandbox_test:            OK (5 scenarios)
transcribefile smoke:    OK

Checklist

  • I understand the code I am submitting.
  • I have run this code locally and verified the change.
  • New and existing tests pass locally, or I have explained why tests were not run.
  • Documentation was updated where necessary. (No user-facing docs describe these
    targets as broken; none needed updating.)
  • If I changed code in llama.cpp/, whisper.cpp/, or stable-diffusion.cpp/, I
    also updated the matching *.patches/ files. — The change is made directly in
    llama.cpp.patches/llamafile-files/BUILD.mk, which apply-patches.sh copies into
    llama.cpp/; nothing in the submodule itself is modified, so no new patch file is
    needed.
  • I have read and followed the contribution guidelines.
  • AI Usage:
    • No AI was used.
    • AI was used in an assistive capacity.
    • This PR includes substantial AI-generated content.

AI Usage Information

  • AI Model used: Claude (Anthropic)

  • AI Developer Tool used: Claude Code

  • Any other info you'd like to share: An AI assistant was used to investigate the
    build failure, draft the BUILD.mk change, write this description, and run the
    verification builds described above. The diagnosis and every command output above
    were reproduced and checked on a real Linux x86-64 build of this repository at the
    stated base commit.

  • I am an AI Agent filling out this form (check box if true)

llama-bench, quantize, imatrix and perplexity each declared prerequisites
in llama.cpp/BUILD.mk but had no link recipe, so make compiled their
objects, printed "Nothing to be done", and exited 0 without producing any
binary. The generic o/$(MODE)/%: o/$(MODE)/%.o rule could not link them
either, because the object path (.../tools/llama-bench/llama-bench.cpp.o)
does not match the pattern the target implies
(.../llama-bench/llama-bench.o). Only llama-server had a recipe.

Add a link recipe for each of the four tools, following the llama-server
pattern and the generic link form in build/rules.mk. They need the same
support objects as llama-server minus the server-only ones, because
llama.cpp.a references them: TOOL_LLAMAFILE_OBJS for the llamafile_*
calls patched into src/llama-mmap.cpp and ggml/src/gguf.cpp, and
HTTPLIB_OBJS plus mbedtls.a for common/download.cpp, common/hf-cache.cpp
and common/license.cpp, which are built with -DLLAMA_USE_HTTPLIB.

Also add main.cpp to TOOL_BENCH_SRCS, TOOL_QUANTIZE_SRCS and
TOOL_PERPLEXITY_SRCS. Upstream keeps main() in a separate main.cpp for
those three tools, so without it they fail to link with an undefined
reference to main. imatrix defines main() in imatrix.cpp and needs no
change.

llama-server is unaffected: rebuilt from the patched BUILD.mk it is
byte-for-byte identical.

Co-Authored-By: Aiden <aiden@weco.ai>
@aittalam

Copy link
Copy Markdown
Member

TYSM @dexhunter ! I appreciate this, I had not added them to the main build because I wanted to test the executables first. I appreciate you added a check that verifies that llama-server is not impacted 🙏

I am trying to wrap up a release by EOD, so I might not be able to merge this immediately, but I am planning to do that right afterwards so we'll have time to play with all the executables before the following release. I hope that's ok, and thanks again!

@dexhunter

Copy link
Copy Markdown
Author

Completely fine — merging after the release makes more sense than merging into it, and it gives the four tools a full cycle before they're in front of anyone. No rush from my side.

On wanting to test the executables first: fair, and the PR description under-delivers there. It only showed --help output and exit codes, which proves the binaries link but not that they do anything. So I put them through a real end-to-end pass to save you part of that work. Built at 811e7c6 on Linux x86-64 with .cosmocc/4.0.2/bin/make, using the TinyLLama-v0.1-5M-F16.gguf that make setup already fetches.

quantize — F16 → Q4_0 across all 75 tensors, 8.82 MiB (16.00 BPW) → 3.46 MiB (6.28 BPW), exit 0.

llama-bench — real timings on that quantized model:

| model         |     size |  params | backend | threads | test |              t/s |
| llama ?B Q4_0 | 3.46 MiB |   4.62 M | CPU     |       4 | pp32 | 2619.81 ± 406.34 |
| llama ?B Q4_0 | 3.46 MiB |   4.62 M | CPU     |       4 | tg16 |   545.87 ±  53.10 |
build: c588c4f47

perplexity — 16 chunks at -c 128, 0.73 s/pass, final estimate emitted, exit 0.

imatrix — 4 chunks, wrote a 29,184-byte GGUF-format importance matrix, exit 0.

The two togetherquantize --imatrix <that file> ... Q4_K_M consumed it and produced a model, exit 0. That cross-tool path is the one I'd most expect a link-only change to get wrong, and it doesn't.

Two things those runs are not: the perplexity and imatrix values are meaningless, because a 5M-parameter toy model over an arbitrary text file will report whatever it likes — read them as "the code path runs to completion and terminates correctly", not as a quality signal. And this was a default-MODE build with asserts enabled, so the t/s figures aren't performance numbers either. If it'd be useful I'm happy to redo any of it in MODE=opt against a real model.

Still current, too: main has moved 5 commits since the branch base, none of them touch BUILD.mk, and the branch merges cleanly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants