Sergio Adan Bermudez

Case study · llama.cpp · Vulkan · 19 to 20 October 2026

A 3-second pause, taken apart

My voice assistant paused about 3 seconds before every answer. The model was fast, so the time had to be going somewhere else. Scroll through the eight measurements that found it.

Voice, first word3.0 s → 0.7 s
One state snapshot0.61 s → 0.03 s
880 MB state read7,738 → 553 ms
01 · ENGINE AGAINST SERVER

The model is not the problem

llama-bench read 16 prompt tokens in 0.11 s. The server took 1.4 to 2.5 s for the same work. The model is a hybrid, Qwen3.6-35B-A3B: part of it keeps a running state instead of a normal attention cache.

02 · SETTINGS

Ruled out on a test server

Batch size, context size and slot count, each changed on a separate server on a spare port so production stayed untouched. None moved the delay.

03 · TIMESTAMPED LOGS

Two snapshots, 0.6 s each

To resume a conversation after its text changes, the server saves snapshots of the model's running state: 63 MB each, two per request. Those two saves were the whole delay.

04 · A CHANGE I REVERTED

Faster voice, broken agent

With snapshots off, voice answered in 0.5 s. But the agent re-formats its previous reply slightly, and a hybrid model cannot step its state back without a snapshot, so it re-read its 13,700-token prompt every turn. My first tests used voice-style conversations only; the full test of every service caught it.

05 · NEWER BUILD, FOUR SWITCHES

No change

A newer engine build and four Vulkan settings gave the same timings. The cost was in the code.

06 · A PATCH THAT FAILED

Skipping GPU waits saved nothing

Each saved tensor goes through a synchronous GPU barrier and wait. Skipping the redundant ones took a snapshot from 0.65 s to 0.61 s. Discarded.

07 · TIMERS ON THE READ PATH

114 MB per second

The waits took 14 ms in total. The CPU copy took 7,738 ms for 880 MB. On this integrated GPU the memory is visible to the CPU but not cached by it, so every read crawls.

08 · ONE CONDITION

Read directly only from cached memory

Otherwise let the GPU copy into a cached staging buffer first, then read that.

// ggml_vk_buffer_read_2d(): direct host read only when it is fast
if (src->memory_property_flags & vk::MemoryPropertyFlagBits::eHostVisible &&
    src->device->uma &&
    src->memory_property_flags & vk::MemoryPropertyFlagBits::eHostCached) {
time budgetstep 1 of 8

Verification

Same answers, word for word

  • The same scripted six-turn conversation at temperature 0 ran on the stock and fixed builds, in two modes: history resent verbatim, and history altered so the server must restore a snapshot.
  • Replies were identical word for word in both modes; snapshot restores 4 of 4 in each build.
  • The exact deployment, one library swapped, was rehearsed on a copy of the engine folder first, with a backup and a one-step undo.

Outcome. After deploying, I found that the Vulkan backend's maintainer had merged the same fix two weeks earlier (llama.cpp #30049), prompted by a benchmark on the same GPU. My engine version predated it. This is an independent diagnosis, not an upstream contribution. I now check a file's recent history before patching it.

Results

MeasuredBeforeAfterMain cause
Voice, time to first word≈ 3 s≈ 0.7 sEngine fix, voice-only sampling setting
Agent, each later turn3.5 s1.1 to 1.4 sEngine fix, smaller prompt
Agent, new conversation2.5 s1.2 sEngine fix
Agent, task with code tool43.5 s23.0 sEngine fix
Agent, task with web search11.7 s7.1 sEngine fix
One state snapshot0.61 s0.03 sCached read path
Agent prompt per request13,718 tok11,560 tokRemoved two unused tools

The first turn after the model loads is unchanged: the agent still reads its 11,600-token instructions once, about 21 to 24 s.

Method

How it was built and tested

I designed and directed this work; the code, builds and measurements were carried out by Claude Code running as my agent, with every change to a running system approved by me first. I set the goals (faster voice and agent, no lost function, no cloud inference), chose the trade-offs, and decided what to deploy and when to revert.

llama.cpp (C++, Vulkan) · Visual Studio 2022 Build Tools · Vulkan SDK · llama-bench · Python harnesses · Docker · WSL