<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: bossandboss</title>
    <description>The latest articles on DEV Community by bossandboss (@bossandboss).</description>
    <link>https://dev.to/bossandboss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4009729%2F8edf271b-c81f-4eb1-8004-570f9dc6049d.png</url>
      <title>DEV Community: bossandboss</title>
      <link>https://dev.to/bossandboss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bossandboss"/>
    <language>en</language>
    <item>
      <title>I Got 9.9 Lower TTFT on a Real Android Phone by Reusing llama.cpp KV State</title>
      <dc:creator>bossandboss</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:17:57 +0000</pubDate>
      <link>https://dev.to/bossandboss/i-got-99x-lower-ttft-on-a-real-android-phone-by-reusing-llamacpp-kv-state-1ngi</link>
      <guid>https://dev.to/bossandboss/i-got-99x-lower-ttft-on-a-real-android-phone-by-reusing-llamacpp-kv-state-1ngi</guid>
      <description>&lt;p&gt;Local LLM inference has an expensive habit:&lt;br&gt;
It recomputes prefixes it has already seen.&lt;br&gt;
A system prompt.&lt;br&gt;
A reused RAG document.&lt;br&gt;
A few-shot block.&lt;br&gt;
A long static context.&lt;br&gt;
If the prefix is identical, why pay the prefill cost again?&lt;br&gt;
That's the problem I explored with EdgeSync-LLM.&lt;br&gt;
The idea&lt;br&gt;
The mechanism is simple:&lt;br&gt;
Prompt = shared prefix + new suffix&lt;br&gt;
On the first request, EdgeSync prefills the prefix and captures its KV cache state.&lt;br&gt;
On the next request sharing that exact prefix, it restores the state and decodes only the new suffix.&lt;br&gt;
No llama.cpp fork.&lt;br&gt;
No patch.&lt;br&gt;
The current validated path uses the public:&lt;br&gt;
llama_state_seq_get_data&lt;br&gt;
and&lt;br&gt;
llama_state_seq_set_data&lt;br&gt;
APIs.&lt;br&gt;
Measured on a real Android ARM64 phone&lt;br&gt;
Model:&lt;br&gt;
Qwen2.5-0.5B-Instruct Q4_K_M&lt;br&gt;
Shared prefix:&lt;br&gt;
123 tokens&lt;br&gt;
40 requests. 4 threads. Release build.&lt;br&gt;
Path&lt;br&gt;
Mean TTFT&lt;br&gt;
p50&lt;br&gt;
p95&lt;br&gt;
Cold&lt;br&gt;
4828 ms&lt;br&gt;
4752 ms&lt;br&gt;
5297 ms&lt;br&gt;
KV state reuse&lt;br&gt;
486 ms&lt;br&gt;
476 ms&lt;br&gt;
569 ms&lt;br&gt;
9.9× lower TTFT on cache hits.&lt;br&gt;
The warm path was approximately:&lt;br&gt;
363 ms to decode the 10-token suffix&lt;br&gt;
123 ms to restore the state blob&lt;br&gt;
Fragment size: 1.64 MB&lt;br&gt;
I also measured the same mechanism on x86-64.&lt;br&gt;
Cold mean TTFT: 1395 ms&lt;br&gt;
Warm mean TTFT: 185 ms&lt;br&gt;
That's 7.5× on cache hits.&lt;br&gt;
But I almost published a fake 8.8× speedup&lt;br&gt;
This was the most important part of the project.&lt;br&gt;
My first implementation directly copied raw K/V tensors.&lt;br&gt;
It was fast.&lt;br&gt;
Very fast.&lt;br&gt;
The benchmark reported an 8.8× speedup.&lt;br&gt;
There was one problem.&lt;br&gt;
It was wrong.&lt;br&gt;
llama.cpp tracks more than the K/V tensor values. Cache cells also have position and sequence metadata used to construct the attention mask.&lt;br&gt;
Copying tensor values without restoring that bookkeeping produced an inert fragment.&lt;br&gt;
The model skipped prefix computation...&lt;br&gt;
...but attention could not actually see the restored prefix.&lt;br&gt;
14 of 24 cache hits reproduced, token for token, the output of a generation with no prefix at all.&lt;br&gt;
The “speedup” was dropped context.&lt;br&gt;
So I discarded it.&lt;br&gt;
Timing is not enough&lt;br&gt;
A broken cache can be fast.&lt;br&gt;
That's why EdgeSync now runs two correctness checks.&lt;br&gt;
First:&lt;br&gt;
Warm output must match cold output for the same prompt.&lt;br&gt;
Results:&lt;br&gt;
ARM64: 28/28&lt;br&gt;
x86-64: 24/24&lt;br&gt;
Second:&lt;br&gt;
The warm output is compared with a generation from the suffix alone, without the prefix.&lt;br&gt;
If both outputs match, the injected fragment may be doing nothing.&lt;br&gt;
Results:&lt;br&gt;
ARM64: 0/28 matches&lt;br&gt;
x86-64: 0/24 matches&lt;br&gt;
This second control is what caught the broken raw-tensor implementation.&lt;br&gt;
A latency benchmark alone would not have caught it.&lt;br&gt;
What I learned&lt;br&gt;
There is a broader lesson here for LLM infrastructure benchmarking:&lt;br&gt;
Skipping computation is not proof that state reuse works.&lt;br&gt;
If a cache implementation silently drops context, it can look extremely fast.&lt;br&gt;
Correctness must be part of the benchmark.&lt;br&gt;
Not a separate test.&lt;br&gt;
Not an assumption.&lt;br&gt;
Part of the measurement itself.&lt;br&gt;
What EdgeSync does not claim&lt;br&gt;
I deliberately marked several parts of the project as unvalidated or unsound.&lt;br&gt;
Semantic approximate prefix reuse is not proven.&lt;br&gt;
Reusing KV state between merely “similar” prefixes is incorrect with the current mechanism.&lt;br&gt;
Cross-engine reuse does not work with opaque llama.cpp sequence-state blobs.&lt;br&gt;
Per-layer striding cannot preserve output.&lt;br&gt;
The Android JNI bridge and several cache management components still need end-to-end validation.&lt;br&gt;
The on-device ARM64 sampling is also thin and needs to be rerun with more timed repeats.&lt;br&gt;
I would rather publish a smaller result that can be falsified than a larger claim that cannot survive reproduction.&lt;br&gt;
What's next&lt;br&gt;
The next steps are:&lt;br&gt;
Rerun ARM64 with multiple timed repeats.&lt;br&gt;
Compare complete generated strings instead of one token.&lt;br&gt;
Benchmark HNSW against an exact radix-tree lookup.&lt;br&gt;
Measure state restoration cost as prefix length increases.&lt;br&gt;
Remove or redefine the current PARTIAL-hit mechanism.&lt;br&gt;
The code, benchmark methodology and measured manifests are public.&lt;br&gt;
EdgeSync-LLM:&lt;br&gt;
&lt;a href="https://github.com/bossandboss/EdgeSync-LLM" rel="noopener noreferrer"&gt;https://github.com/bossandboss/EdgeSync-LLM&lt;/a&gt;&lt;br&gt;
If you work on llama.cpp, local LLM inference, KV cache management or edge AI, I would especially value attempts to reproduce or break the benchmark.&lt;br&gt;
Finding a flaw is more useful to me than a GitHub star.&lt;/p&gt;

&lt;h1&gt;
  
  
  llm #cpp #android #ai
&lt;/h1&gt;

</description>
      <category>android</category>
      <category>llm</category>
      <category>performance</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
