Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
where the backend cannot provide it, `OFF` disables it.

### Changed
- **llama.cpp `b10731` → `b10819`.** No project-source change: every header move in the range is
- **llama.cpp `b10731` → `b10850`.** No project-source change: every header move in the range is
additive or a **widening** const-qualification, and the server wire contract is byte-identical
(request-field set, `set_hard_limits` bounds and response keys all verified mechanically, which is
the check that catches the contract-behind-a-stable-signature breaks a header diff cannot see).
Expand Down Expand Up @@ -110,6 +110,17 @@ from version 5.0.0 onward. Pre-fork releases (`1.x`–`4.2.0`) were authored by
(`ggml-metal-context.m`, llama.cpp #28399), a SYCL Kronecker-product/FWHT restore (#28254) and
the matching upstream test. Nothing in the review surface, nothing in the server contract.

The `b10819` → `b10850` step is 31 commits and 466 KB in total, but **10 files / +181 / −98**
across the paths this project links against — `common/arg.cpp`, `common/jinja/{caps,runtime}.cpp`,
`common/log.{cpp,h}` and `tools/server/server-models.{cpp,h}` plus that tool's CMake, README and
a router test. Everything else is GPU backends, the WebUI, docs and upstream CI. Two of those
files are patch targets (`common/arg.cpp` for `0001`, `tools/server/server-models.cpp` for
`0008`, the latter with 159 lines rewritten), so the intersection was **not** empty this time and
the applier had to prove it rather than the file list implying it: a fresh configure applied all
eight patches clean and stamped them at head `f114f91f`. The server wire contract was re-checked
mechanically and is byte-identical — request-field set, `set_hard_limits` bounds, and response
keys in **both** emit forms.

- **llama.cpp `b10682` → `b10731`.** One project-source change came out of it, and it is the kind a
header diff does not surface: upstream renamed `--tensor-read-lazy` to `-lzm` / `--lazy-mode`
(env `LLAMA_ARG_TENSOR_READ_LAZY` → `LLAMA_ARG_LAZY_MODE`) **with no alias**. The binding emitted
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

Java bindings for [llama.cpp](https://github.com/ggerganov/llama.cpp) via JNI, providing a high-level API for LLM inference in Java. The Java layer communicates with a native C++ library through JNI.

Current llama.cpp pinned version: **b10819**
Current llama.cpp pinned version: **b10850**

## Upgrading CUDA Version

Expand Down Expand Up @@ -490,7 +490,7 @@ needs no extra step here, `build-webui` re-reads the tag and rebuilds the matchi
ships no UI):
```bash
# needs node/npm + network; embed.cpp is plain C++17 (no npm)
git clone --depth 1 --branch b10819 https://github.com/ggml-org/llama.cpp /tmp/lc
git clone --depth 1 --branch b10850 https://github.com/ggml-org/llama.cpp /tmp/lc
( cd /tmp/lc/tools/ui && npm ci && npm run build \
&& ( cd dist && find . -type f -not -path './_gzip/*' \
| while read -r f; do mkdir -p "_gzip/$(dirname "$f")"; gzip -9 -c "$f" > "_gzip/$f"; done ) \
Expand Down Expand Up @@ -530,7 +530,7 @@ cache lives in **Depot Cache** over sccache's **WebDAV** backend:
- `SCCACHE_WEBDAV_TOKEN: ${{ secrets.DEPOT_TOKEN }}` — a Depot **organization** token, stored
as the repo secret **`DEPOT_TOKEN`**.

Because `sccache` is **content-addressed** and llama.cpp is pinned (`GIT_TAG b10819`), the
Because `sccache` is **content-addressed** and llama.cpp is pinned (`GIT_TAG b10850`), the
~280 upstream object files are byte-identical every run, so a warm cache recompiles only the
*changed* files. Depot's cache is **shared across all branches** (unlike GitHub's
per-branch `actions/cache`), so every branch builds incrementally; a `b<nnnn>` version bump
Expand Down Expand Up @@ -1451,7 +1451,7 @@ ctest --test-dir build --output-on-failure -R "ResultsToJson"

#### Upstream source location (in CMake build tree)

llama.cpp is fetched via CMake FetchContent, pinned to `GIT_TAG b10819`.
llama.cpp is fetched via CMake FetchContent, pinned to `GIT_TAG b10850`.

**GoogleTest** is a separate `BUILD_TESTING`-only FetchContent (`GIT_TAG v1.17.0`), used solely
by the `jllama_test` C++ unit-test binary — not by the shipped library, and not coupled to the
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
**Build:**
![Java 8+](https://img.shields.io/badge/Java-8%2B-informational)
![Platform](https://img.shields.io/badge/Platform-Linux%20%7C%20macOS%20%7C%20Windows%20%7C%20Android-lightgrey)
[![llama.cpp b10819](https://img.shields.io/badge/llama.cpp-%23b10819-informational)](https://github.com/ggml-org/llama.cpp/releases/tag/b10819)
[![llama.cpp b10850](https://img.shields.io/badge/llama.cpp-%23b10850-informational)](https://github.com/ggml-org/llama.cpp/releases/tag/b10850)
[![JPMS](https://img.shields.io/badge/JPMS-modular%20JAR-25A162)](https://openjdk.org/projects/jigsaw/)
![JUnit](https://img.shields.io/badge/tested%20with-JUnit6-25A162)
[![JSpecify](https://img.shields.io/badge/JSpecify-1.0.0%20%40NullMarked-25A162)](https://jspecify.dev)
Expand Down
4 changes: 3 additions & 1 deletion docs/history/llama-cpp-breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -694,4 +694,6 @@ Used during `llama.cpp` version bumps: when upgrading, scan this file from the r
| b10797–b10817 | patches + upstream verification | **Zero intersection with the patch set.** The 42 files the eight patches touch were intersected against the range's changed-file list: empty, so no patch context can have moved. The applier was run for real anyway — fresh `rm -rf build && cmake -B build -DBUILD_TESTING=ON`, configure clean, stamp at `head cd8cdf397dc21d986e69069ce2180651d693fdff`, all eight hashes recorded. **Chunking:** the full diff is 307 KB, over the runbook's 100 KiB threshold, but excluding `ggml/src/**`, `tools/ui/**`, `docs/**`, `.github/**` and `conversion/**` — every one of them outside the review surface the rule exists to bound — it is **68 KB, under the threshold**. Same call as the previous bump, and this time the excluded-diff figure alone justifies it. This range does not address the macOS-15 failure; see the investigation row at the end of this table, which **refutes** the #28323 suspicion recorded here and shows the b10792–b10797 window itself was never established. |
| b10817–b10819 | `ggml/src/ggml-metal/ggml-metal-context.m` (**#28399: one-line memory-leak fix on an early-return path**), `ggml/src/ggml-sycl/fwht.cpp` (#28254: restore Kronecker-product FWHT support and unbreak `test-backend-ops` on SYCL), `tests/test-backend-ops.cpp`. | **No project-source change, and the review surface is empty**: all three changed files are ggml backends or upstream tests, none of which this project links against or compiles into `jllama`. The server contract was re-checked and is byte-identical (request-field set, response keys in both emit forms); `tools/server/`, `common/`, `include/`, `tools/mtmd/` and `ggml/include/` have no change at all in the range. The Metal leak fix sits next to the **macOS-15 failure** and is not a fix for it; the investigation row below supersedes the reasoning recorded here, including the claim that "the no-Metal macOS job fails identically" (there was no no-Metal job). |
| b10817–b10819 | patches + upstream verification | **Zero intersection with the patch set**: the 42 files the eight patches touch versus the range's 3 changed files — empty, so no patch context can have moved. The applier was run for real regardless: fresh `rm -rf build && cmake -B build -DBUILD_TESTING=ON`, configure clean, stamp at `head 6a1a922d269908a29cbd4b49c27e6a8e7fd10fae`, all eight hashes recorded. **No chunking question arises**: the full diff is 17 KB across 2 commits, far inside the runbook's 100 KiB threshold, so this is a straight bump *by* the rule rather than an exception to it. |
| **macOS-15 failure — investigation, 2026-09-05** | `Java Tests macOS 15 arm64 (Metal)` + `(no Metal)`, run **33861339600** (#897, dispatch, pin b10797) | **The #28323 lead is refuted, and the b10792–b10797 bisect window it rested on was never established.** Read this row before spending time on the earlier suspicion recorded two rows up. **What actually fails.** Two tests, `MemoryManagementTest#testPromptCacheCompleteMissAfterWarmup` and `LlamaModelTest#testSpeculativeDecoding`, both with `LlamaException: could not load model from given file path` over a native `llama_model_load: error loading model: vector`. The recorded symptom ("the draft model") is **half wrong**: the first failure is **codellama-7b.Q2_K.gguf**, the second the AMD-Llama-135m draft — so it is not size-specific. Both are *repeat* loads: the same 7B model had already loaded and generated successfully dozens of times in the same JVM over the preceding ten minutes. `what() == "vector"` is libc++'s message for `std::out_of_range` from `vector::at()` and for `vector`'s `length_error`; the 33 ms elapsed (10.06.078 → 10.06.111) and the position right after the vocab warnings put it in `load_hparams`/`load_tensors`, not in the big allocation phase. **Why #28323 cannot be it — three independent reasons.** `n_expert_used_arr` is a `std::array<uint32_t, LLAMA_MAX_LAYERS>` read through `operator[]` behind an `il < n_layer_all` guard, so it cannot raise `out_of_range("vector")` (and its failure mode would be `GGML_ABORT`, which aborts rather than throws). Both failing models are dense (`n_expert == 0`), so the two changed call sites in `weight_buft_supported` (`GGML_OP_MUL_MAT_ID`, `GGML_OP_ADD_ID`) are unreachable and the `load_tensors` guard short-circuits on `n_expert > 0` before ever calling it. And the change is a **widening** — `max(il)` ≥ `[0]` — so it cannot narrow a value into an out-of-range one. **The "no Metal" job has never been a no-Metal job**, which invalidates the "both macOS jobs fail identically, so Metal is not involved" reasoning. It passed `-DLLAMA_METAL=OFF`, and upstream's `llama_option_depr(WARNING LLAMA_METAL GGML_METAL)` forwards only `if (${OLD})` — i.e. it acts on `ON` and **silently ignores `OFF`**, leaving `GGML_METAL` at its `APPLE` default of `ON`. CMake emits no "unused variable" warning either, because the variable *is* read; it just has no effect. Both macOS-15 jobs were therefore the same Metal build, which is why their logs are identical (44 `MTL0`/`ggml_metal` lines in the supposedly Metal-free one) and why "identical failure" carried no information. Fixed in this change set by passing `-DGGML_METAL=OFF`; the two `-DLLAMA_METAL_EMBED_LIBRARY=ON` sites are unaffected, since the shim does forward a truthy value. **The bisect window is wrong, and much wider than 5 commits.** The last CI observation of the macOS *Java test* jobs passing is run **33275073456** (#875, the v5.1.0 release dispatch, 2026-08-29) at pin **b10618**. b10731 was never observed: run #887 (dispatch, b10731) failed at `Code style (spotless) + package graph`, which skipped everything downstream — 30 jobs, no `Java Tests macOS` among them — and every other run between #875 and #897 was cancelled. So the regression window is **b10618 → b10797**, ~180 upstream builds, not b10792 → b10797. **Memory pressure is not the discriminator**, checked rather than assumed: the *green* run #875 logged **8** `ggml_metal_log_allocated_size: current allocated size is greater than the recommended max working set size` warnings and more free pages than the red run, which logged **6**. The 7 GB runner is tight in both. **Not resolved.** No bisect was run: it needs Apple-silicon hardware or one `workflow_dispatch` per step, neither available in the sandbox this was investigated from. The decisive next steps, in order: (1) dispatch one run on the current `main` (b10819) — nothing on it has been validated by CI at all, so even the premise "still red" is unverified; (2) with the flag fixed, compare the now-genuinely-Metal-free job against the Metal one, which is the experiment the old flag silently prevented; (3) only then bisect, over **b10618…b10797**. |
| **macOS-15 failure — investigation, 2026-09-05** | `Java Tests macOS 15 arm64 (Metal)` + `(no Metal)`, run **33861339600** (#897, dispatch, pin b10797) | **The #28323 lead is refuted, and the b10792–b10797 bisect window it rested on was never established.** Read this row before spending time on the earlier suspicion recorded two rows up. **What actually fails.** Two tests, `MemoryManagementTest#testPromptCacheCompleteMissAfterWarmup` and `LlamaModelTest#testSpeculativeDecoding`, both with `LlamaException: could not load model from given file path` over a native `llama_model_load: error loading model: vector`. The recorded symptom ("the draft model") is **half wrong**: the first failure is **codellama-7b.Q2_K.gguf**, the second the AMD-Llama-135m draft — so it is not size-specific. Both are *repeat* loads: the same 7B model had already loaded and generated successfully dozens of times in the same JVM over the preceding ten minutes. `what() == "vector"` is libc++'s message for `std::out_of_range` from `vector::at()` and for `vector`'s `length_error`; the 33 ms elapsed (10.06.078 → 10.06.111) and the position right after the vocab warnings put it in `load_hparams`/`load_tensors`, not in the big allocation phase. **Why #28323 cannot be it — three independent reasons.** `n_expert_used_arr` is a `std::array<uint32_t, LLAMA_MAX_LAYERS>` read through `operator[]` behind an `il < n_layer_all` guard, so it cannot raise `out_of_range("vector")` (and its failure mode would be `GGML_ABORT`, which aborts rather than throws). Both failing models are dense (`n_expert == 0`), so the two changed call sites in `weight_buft_supported` (`GGML_OP_MUL_MAT_ID`, `GGML_OP_ADD_ID`) are unreachable and the `load_tensors` guard short-circuits on `n_expert > 0` before ever calling it. And the change is a **widening** — `max(il)` ≥ `[0]` — so it cannot narrow a value into an out-of-range one. **The "no Metal" job has never been a no-Metal job**, which invalidates the "both macOS jobs fail identically, so Metal is not involved" reasoning. It passed `-DLLAMA_METAL=OFF`, and upstream's `llama_option_depr(WARNING LLAMA_METAL GGML_METAL)` forwards only `if (${OLD})` — i.e. it acts on `ON` and **silently ignores `OFF`**, leaving `GGML_METAL` at its `APPLE` default of `ON`. CMake emits no "unused variable" warning either, because the variable *is* read; it just has no effect. Both macOS-15 jobs were therefore the same Metal build, which is why their logs are identical (44 `MTL0`/`ggml_metal` lines in the supposedly Metal-free one) and why "identical failure" carried no information. Fixed in this change set by passing `-DGGML_METAL=OFF`; the two `-DLLAMA_METAL_EMBED_LIBRARY=ON` sites are unaffected, since the shim does forward a truthy value. **The bisect window is wrong, and much wider than 5 commits.** The last CI observation of the macOS *Java test* jobs passing is run **33275073456** (#875, the v5.1.0 release dispatch, 2026-08-29) at pin **b10618**. b10731 was never observed: run #887 (dispatch, b10731) failed at `Code style (spotless) + package graph`, which skipped everything downstream — 30 jobs, no `Java Tests macOS` among them — and every other run between #875 and #897 was cancelled. So the regression window is **b10618 → b10797**, ~180 upstream builds, not b10792 → b10797. **Memory pressure is not the discriminator**, checked rather than assumed: the *green* run #875 logged **8** `ggml_metal_log_allocated_size: current allocated size is greater than the recommended max working set size` warnings and more free pages than the red run, which logged **6**. The 7 GB runner is tight in both. **Resolved to Metal by run 33994480652** — see the row below, which carries the experiment this one could only propose. |
| **macOS-15 failure — cause isolated, 2026-09-06** | `Java Tests macOS 15 arm64 (Metal)` vs `(no Metal)`, run **33994480652** (#910, dispatch, pin b10819) | **It is a Metal bug.** The first dispatch after the `-DGGML_METAL=OFF` fix turns the two macOS-15 jobs into a clean single-variable comparison, and they disagree: same runner, same OS, same `-DGGML_NATIVE=OFF`, identical **1742 tests / 11 skipped** on both sides, differing only in `GGML_METAL`. With Metal: **2 errors** — `MemoryManagementTest` 1 of 10 and `LlamaModelTest` 1 of 60, both `llama_model_load: error loading model: vector`, unchanged from #897. Without Metal: **0 errors**, those same classes 10/10 and 60/60, and **zero** `MTL0`/`ggml_metal` lines in the log where the old build had 44 — so the flag fix demonstrably took effect. The standing conclusion "the no-Metal job fails identically, so this is not a Metal problem" was an artifact of the no-op flag and is now retired. **What this does NOT establish:** `Java Tests macOS 14 arm64 (Metal)` is green, but that job differs from the red one in **two** variables at once — OS version *and* `GGML_NATIVE` (macos-14 builds host-native, macos-15 passes `-DGGML_NATIVE=OFF`) — so it cannot narrow "Metal" to "Metal on macOS 15" or to "Metal plus a portable build". Only the macos-15 pair isolates anything. **What it buys.** The bisect window stays b10618 → b10797 in tags, but the *candidate set* collapses from every upstream change to the Metal backend alone (`ggml/src/ggml-metal/**`) — precisely the directory every bump review in this table waved through as "GPU backend, safe to skip". That rule is sound for compile/link breaks and blind to runtime ones; this is the first entry where it cost something. **Still open:** which Metal commit, and whether upstream has since fixed it. The rest of run #910 was green — 51 success, 1 failure, 12 skipped (all downstream of the red job), including `Run PIT mutation tests: success`, which is the first CI confirmation of the PIT gate since the SLF4J classpath fix. |
| b10819–b10850 | `common/arg.cpp` (**additive**: `--log-jsonl` / `--no-log-jsonl`), `common/log.{cpp,h}` (**additive**: `common_log_set_jsonl`, plus a `level_str` helper and a `json.h` include), `common/jinja/{caps,runtime}.cpp`, `tools/server/server-models.{cpp,h}` (**159 lines rewritten**; `request_stop(name)` added to the header), `tools/server/CMakeLists.txt` + `README.md` + `tests/unit/test_router.py`. **`include/`, `ggml/include/` and `tools/mtmd/` are untouched in the range.** | **No project-source change.** The header moves are additive: `common_log_set_jsonl` is new API nothing here calls, and the two new `common_arg` entries are CLI-only. The 159 changed lines in `server-models.cpp` are the router's instance lifecycle, not its argv rendering. **The patch intersection was NOT empty this time** — `common/arg.cpp` (patch `0001`) and `tools/server/server-models.cpp` (patch `0008`) are both in the range, so the applier had to prove the contexts survived rather than a disjoint file list implying it: a fresh `rm -rf build && cmake -B build -DBUILD_TESTING=ON` applied all eight clean and stamped them at head `f114f91f9ed6792cf402437e3874adad98902744`. Server contract re-checked mechanically and byte-identical (request-field set, `set_hard_limits` bounds, response keys in both emit forms). **Chunking, with the figures recorded rather than a verdict asserted:** the full diff is **466 KB over 31 commits**; excluding the paths this table's earlier rows excluded (`ggml/src`, `tools/ui`, `docs`, `.github`, `conversion`) it is still **171 KB**, over the runbook's 100 KiB threshold — but that figure is misleading, because the remainder is dominated by `scripts/ui-assets.cmake`, `tests/test-backend-ops.cpp`, a new model architecture (`src/models/spark2-5.cpp` + its Jinja template) and `gguf-py/`, none of which the project links against and none of which the old exclusion list names. The **review surface proper** — `common/`, `include/`, `tools/server/`, `tools/mtmd/`, `ggml/include/`, top-level `CMakeLists.txt` — is **27 KB / 10 files / +181 / −98**, comfortably inside the threshold. Recorded both ways so the call is auditable. **Metal moved in this range too** (`ggml-metal-device.m` +7/−2 and a new 147-line `ggml-metal-tuning.cpp`), which matters only because of the macOS-15 finding in the row below: this bump neither targets nor is known to fix it. |
Loading
Loading