vram-lend 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ docs/drafts/
2
+ __pycache__/
3
+ .venv/
4
+ dist/
5
+ *.egg-info/
6
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TacoTakumi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.5
2
+ Name: vram-lend
3
+ Version: 0.1.0
4
+ Summary: Lend yourself GPU memory from a serving inference engine, run a job, give it back
5
+ Project-URL: Homepage, https://github.com/TacoTakumi/vram-lend
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: agent,gpu,llama-swap,llama.cpp,skill,vram
9
+ Classifier: Environment :: Console
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: agentsquire>=0.5.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ # VRAM Lend
17
+
18
+ VRAM Lend lets an inference engine lend part of its GPU memory to another
19
+ program on the same machine while it keeps serving requests, and take the
20
+ memory back after.
21
+
22
+ A large MoE model on consumer GPUs fills every GPU, mostly with its expert
23
+ cache: copies of experts that also live in RAM or on disk. An image
24
+ generator, a speech service or a small helper model needs a few GiB on one
25
+ GPU for a short time. With VRAM Lend the engine empties that many MiB of its
26
+ expert cache on the GPU asked for and releases them to the driver at once.
27
+ The borrower allocates the memory, uses it and frees it, and a return gives
28
+ it back to the engine. The engine never stops serving.
29
+
30
+ ```
31
+ POST /vram/lend {"gpu": "0000:09:00.0", "mib": 8192} -> {"id": "7", "gpu": "0000:09:00.0", "mib": 8208}
32
+ POST /vram/return {"id": "7"} -> {"id": "7", "gpu": "0000:09:00.0", "mib": 8208}
33
+ GET /vram/state -> {"gpus": [...], "leases": [...]}
34
+ ```
35
+
36
+ ## Status
37
+
38
+ | Component | Status | Code |
39
+ |---|---|---|
40
+ | Project Maya (GLM-5.3-Flash and DeepSeek-V4.1 engines) | Done: lend and return on any GPU while requests run | Fork branch: <https://github.com/TacoTakumi/project-maya/tree/vram-lend>. Upstream PR: not opened yet |
41
+ | Strata | Lend and return on both GPUs of a 2x RTX 3090 layer split while requests run | Fork branch: <https://github.com/TacoTakumi/Strata/tree/vram-lend>, on [Niko1221/Strata](https://github.com/Niko1221/Strata) v0.2.7.1 with upstream PR [#2522](https://github.com/Niko1221/Strata/pull/2522), which now carries the four fixes from this work as its own commits. Upstream issue: [#4168](https://github.com/Niko1221/Strata/issues/4168) |
42
+ | llama.cpp | Done: lend and return of the MoE expert cache on any GPU that has one, while requests run. Served on this host through llama-swap as its own entry | Fork branch: <https://github.com/TacoTakumi/llama.cpp/tree/vram-lend>, on master 961c376a2 with the per-device `--moe-cache-mib` of [#30205](https://github.com/ggml-org/llama.cpp/pull/30205). Upstream PR: not opened yet |
43
+ | llama-swap (one address for every engine) | Done as a general change: a request matching `upstream.ignorePaths` on a loaded model is served outside the scheduler (no start, no concurrency slot, no in-flight count, no ttl reset), so `/upstream/<model>/vram/lend`, `/vram/return` and `/vram/state` with `^/vram/` in `ignorePaths` reach a serving engine and never load one. Ten lines of logic, tests, docs. See [docs/llama-swap.md](docs/llama-swap.md) | Fork branch: <https://github.com/TacoTakumi/llama-swap/tree/untracked-paths>, on [mostlygeek/llama-swap](https://github.com/mostlygeek/llama-swap) 6c855da (v267). Upstream issue: [#1135](https://github.com/mostlygeek/llama-swap/issues/1135), existing. Upstream PR: not opened yet. Replaces the earlier `vram-route` branch (a `/vram` route on llama-swap's own port, routed by card) |
44
+ | `vram-lend` command and agent skill (borrower side) | Done: one command that finds the engine, directly or behind llama-swap, lends on the card named, runs the job and returns the lease when the job exits; a skill that teaches an agent when and how to use it. See [Agent instructions](#agent-instructions) | This repository: `src/vram_lend/`, the skill in `src/vram_lend/skills/vram-lend/`. Package `vram-lend` on PyPI |
45
+ | Berth (broker side) | Done on one GPU, as an experimental feature of the v0.4.0 pre-releases (rc.3 tested on this host: a 6.5 GiB voice borrower on an RTX 4060 Ti held by Maya, lend, grant and take back while Maya streams). Several GPUs under one lease are planned | [v0.4.0-rc.3](https://github.com/T-Crypt/berth/releases/tag/v0.4.0-rc.3), [contrib/LEND-PROTOCOL.md](https://github.com/T-Crypt/berth/blob/next/contrib/LEND-PROTOCOL.md). Design and tests: <https://github.com/T-Crypt/berth/issues/189> |
46
+
47
+ ## Results
48
+
49
+ Maya fork, final builds before and after the rebase onto upstream v1.1.27
50
+ (the results pages give the build of each row), on 2x RTX 3090, RTX 5060 Ti
51
+ and 2x RTX 4060 Ti. An 8 GiB lend on an RTX 4060 Ti while a request streams:
52
+
53
+ | Check | GLM-5.3-Flash | DeepSeek-V4.1 |
54
+ |---|---|---|
55
+ | Lend answer / driver shows the memory free | 0.36-0.41 s / 0.01-0.04 s after | 0.16-0.22 s / 0.01-0.05 s after |
56
+ | Largest token gap, lend / return | 0.40-0.45 s / 0.16-0.23 s | 0.23-0.28 s / 0.12-0.21 s |
57
+ | Return answer | 0.05-0.07 s | 0.08-0.13 s |
58
+ | 2 GiB on each GPU, other GPUs | all pass, 0 MiB change | all pass, 0 MiB change |
59
+ | Prompt rate at full lendable | 91% of the rate with nothing lent | 85-98% |
60
+ | Lendable before the lend = after the return | 10320 = 10320 MiB | 10478 = 10478 MiB |
61
+ | Decode with 8 GiB lent | within noise (52.5 / 50.8 / 52.2 and 47.7 / 48.8 / 49.3 t/s before / lent / after) | no penalty visible |
62
+
63
+ Over lendable (409), two leases on one GPU, a return while the memory is in
64
+ use (409, retry), a lend during a long prompt read, a late lease given back by
65
+ the server, and an engine restart all pass.
66
+
67
+ Strata fork, branch `vram-lend`, Swift 1.5 IQ4_XS on a layer split over the
68
+ 2x RTX 3090 (0000:01:00.0 on a 24.4 GB/s PCIe link, 0000:02:00.0 on a
69
+ 6.1 GB/s link). An 8 GiB lend on each RTX 3090 while a request streams:
70
+
71
+ | Check | 0000:01:00.0 | 0000:02:00.0 |
72
+ |---|---|---|
73
+ | Lend answer / driver shows the memory free | 0.04-0.05 s / 0.01-0.04 s after | 0.04-0.05 s / 0.01-0.02 s after |
74
+ | Largest token gap, lend / return | 0.046-0.056 s / 0.029-0.039 s | 0.053-0.055 s / 0.067-0.074 s |
75
+ | Return answer | 0.01-0.02 s | 0.02-0.03 s |
76
+ | 2 GiB on each GPU, other GPUs | all pass, 0 MiB change | all pass, 0 MiB change |
77
+ | Prompt rate at full lendable | 98.5-99.7% of the rate with nothing lent | 69-73%: Failed against the 90% target, accepted as the slow link's cost |
78
+ | Lendable before the lend = after the return | 12800 = 12800 MiB | 12288 = 12288 MiB |
79
+ | Decode with 8 GiB lent | -5.6 / -6.5% (hit rate 99.6 to 98.3%) | -11.5 / -9.5% (hit rate 99.6 to 97.2%) |
80
+
81
+ A lend during a long prompt read is answered at the next prompt chunk. Over
82
+ lendable, two leases on one GPU, a return while the memory is in use, an
83
+ engine restart, 50 lend/return cycles during streaming requests and the
84
+ quality suite with 8 GiB lent on each GPU all pass. A late lend (503) was
85
+ not reachable, because the engine answers inside the server's wait; the
86
+ server's unit tests cover that path. HIP and SYCL builds were not run.
87
+
88
+ llama.cpp fork, branch `vram-lend`, the same Swift 1.5 IQ4_XS with its MTP
89
+ draft head and vision encoder on an explicit split over all five GPUs. The
90
+ experts of 14 layers stay in host RAM behind an 8192 MiB MoE expert cache on
91
+ the RTX 5060 Ti (0000:05:00.0) and on one RTX 4060 Ti (0000:09:00.0); those
92
+ two cards lend 8112 MiB each. An 8 GiB lend on 0000:05:00.0 while a request
93
+ streams:
94
+
95
+ | Check | 0000:05:00.0 |
96
+ |---|---|
97
+ | Lend answer / driver shows the memory free | 0.04-0.05 s / at or before the answer |
98
+ | Largest token gap, lend / return | 0.11 s / 0.11-0.12 s |
99
+ | Return answer | 0.03-0.10 s |
100
+ | 2 GiB on each lending GPU, other GPUs | all pass, 0 MiB change |
101
+ | Prompt rate at full lendable | 101% of the rate with nothing lent (the prompt path reads host experts directly) |
102
+ | Lendable before the lend = after the return | 8112 = 8112 MiB, 20 cycles |
103
+ | Decode with 8 GiB lent | 25.0 t/s against 58.3 t/s (the host-expert rate: a full lend leaves each expert group its floor only); back within 5% on the first 300-token run after the return |
104
+
105
+ Over lendable, two leases on one GPU, a return while the memory is in use
106
+ (409, retry), a lend during a 63k-token prompt read (answered at the next
107
+ batch, 1.2-1.4 s), a late lend (503 with a 1 ms wait), an engine restart,
108
+ and the quality suite (coding 16/16, math 12/12, needles 6/6 at 32k and 128k
109
+ with both cards fully lent) all pass. Three lend cycles under the CUDA memory
110
+ checker: 0 errors. The lend-ready layout itself costs 36% of the prompt rate
111
+ against the plain split (18 GiB of experts read from host RAM) and nothing
112
+ on decode. HIP and SYCL builds were not run. The full tables are in
113
+ [bench/results/](bench/results/).
114
+
115
+ ## Agent instructions
116
+
117
+ An agent that needs GPU memory for a short job on a machine where a model is
118
+ served - an Android emulator with `-gpu host`, a speech or image service, a
119
+ small test model, a bench - can lend it from the engine with the `vram-lend`
120
+ command instead of stopping the model. The engine keeps serving, a little
121
+ slower, until the lease is returned.
122
+
123
+ Install the command and the skill:
124
+
125
+ ```
126
+ pipx install vram-lend # or: pip install vram-lend
127
+ vram-lend skills install # the skill, into every agent harness on the machine
128
+ ```
129
+
130
+ `skills install` finds Claude Code, pi, Hermes and opencode and copies the
131
+ skill into each one's user skills directory (`--scope project` for the
132
+ current repository only, `--harness NAME` for one harness). `skills status`
133
+ and `skills update` keep it current. The skill tells the agent to find the
134
+ card, read `vram-lend state`, run the job under `vram-lend run`, and what
135
+ each refusal means. It also tells it what it must never do: start, swap or
136
+ restart a model, guess ports, or use memory after a refusal.
137
+
138
+ The command itself is one Python file with no dependencies outside the
139
+ standard library, `src/vram_lend/lend.py`. Without pip, copy it onto PATH as
140
+ `vram-lend` and copy `src/vram_lend/skills/vram-lend/` into the harness's
141
+ skills directory by hand (`/home/you/.claude/skills/` for Claude Code,
142
+ `/home/you/.pi/agent/skills/` for pi).
143
+
144
+ One run, with the default server `http://127.0.0.1:8080` (llama-swap) and
145
+ the job on the first RTX 4060 Ti:
146
+
147
+ ```
148
+ vram-lend state
149
+ vram-lend run --gpu 0000:09:00.0 --mib 2048 emulator -avd Pixel_8 -gpu host
150
+ ```
151
+
152
+ `run` lends 2048 MiB on that card from whichever serving engine lists it,
153
+ starts the emulator with the lease in its environment, and returns the lease
154
+ when the emulator exits, also on a signal. For a job that is stopped later,
155
+ `vram-lend lend` prints the lease and `vram-lend return --id <id> --endpoint
156
+ <endpoint>` gives it back. `--server URL` or `VRAM_LEND_SERVER` names an
157
+ engine port or another llama-swap; `VRAM_LEND_API_KEY` carries llama-swap's
158
+ key. The verbs mirror
159
+ the HTTP API in [docs/api.md](docs/api.md), and the skill itself is at
160
+ [src/vram_lend/skills/vram-lend/SKILL.md](src/vram_lend/skills/vram-lend/SKILL.md).
161
+
162
+ ## Documentation
163
+
164
+ - [docs/api.md](docs/api.md): the HTTP API (`/vram/lend`, `/vram/return`,
165
+ `/vram/state`), status codes and lease rules.
166
+ - [docs/llama-swap.md](docs/llama-swap.md): the same API through
167
+ llama-swap's `/upstream/<model>/` passthrough for every engine it runs:
168
+ the `ignorePaths` entry, what a call does on a loaded and an unloaded
169
+ model, the fork branch that keeps a call outside the scheduler, the Berth
170
+ `lend_url`, status codes and common failures.
171
+ - [docs/engine-protocol.md](docs/engine-protocol.md): the control lines
172
+ between the server and the engine (`LEND`, `RETURN`, `LENDABLE`), when the
173
+ engine answers, answer order and late leases.
174
+ - [docs/implementing.md](docs/implementing.md): how to add VRAM Lend to an
175
+ engine: the VMM pool, the order before an unmap, the lendable rule, and the
176
+ lessons from the defects found.
177
+ - [docs/research/findings.md](docs/research/findings.md): prior art, where
178
+ the memory is, what a lend costs, and why the memory must go back to the
179
+ driver. Also [glossary.md](docs/research/glossary.md) and
180
+ [questions.md](docs/research/questions.md).
181
+ - [bench/README.md](bench/README.md): the scripts behind the results.
182
+
183
+ ## Licence
184
+
185
+ MIT, see [LICENSE](LICENSE). The Maya fork branch keeps the licence of
186
+ Project Maya, the Strata and llama.cpp fork branches the licences of those
187
+ projects.
@@ -0,0 +1,172 @@
1
+ # VRAM Lend
2
+
3
+ VRAM Lend lets an inference engine lend part of its GPU memory to another
4
+ program on the same machine while it keeps serving requests, and take the
5
+ memory back after.
6
+
7
+ A large MoE model on consumer GPUs fills every GPU, mostly with its expert
8
+ cache: copies of experts that also live in RAM or on disk. An image
9
+ generator, a speech service or a small helper model needs a few GiB on one
10
+ GPU for a short time. With VRAM Lend the engine empties that many MiB of its
11
+ expert cache on the GPU asked for and releases them to the driver at once.
12
+ The borrower allocates the memory, uses it and frees it, and a return gives
13
+ it back to the engine. The engine never stops serving.
14
+
15
+ ```
16
+ POST /vram/lend {"gpu": "0000:09:00.0", "mib": 8192} -> {"id": "7", "gpu": "0000:09:00.0", "mib": 8208}
17
+ POST /vram/return {"id": "7"} -> {"id": "7", "gpu": "0000:09:00.0", "mib": 8208}
18
+ GET /vram/state -> {"gpus": [...], "leases": [...]}
19
+ ```
20
+
21
+ ## Status
22
+
23
+ | Component | Status | Code |
24
+ |---|---|---|
25
+ | Project Maya (GLM-5.3-Flash and DeepSeek-V4.1 engines) | Done: lend and return on any GPU while requests run | Fork branch: <https://github.com/TacoTakumi/project-maya/tree/vram-lend>. Upstream PR: not opened yet |
26
+ | Strata | Lend and return on both GPUs of a 2x RTX 3090 layer split while requests run | Fork branch: <https://github.com/TacoTakumi/Strata/tree/vram-lend>, on [Niko1221/Strata](https://github.com/Niko1221/Strata) v0.2.7.1 with upstream PR [#2522](https://github.com/Niko1221/Strata/pull/2522), which now carries the four fixes from this work as its own commits. Upstream issue: [#4168](https://github.com/Niko1221/Strata/issues/4168) |
27
+ | llama.cpp | Done: lend and return of the MoE expert cache on any GPU that has one, while requests run. Served on this host through llama-swap as its own entry | Fork branch: <https://github.com/TacoTakumi/llama.cpp/tree/vram-lend>, on master 961c376a2 with the per-device `--moe-cache-mib` of [#30205](https://github.com/ggml-org/llama.cpp/pull/30205). Upstream PR: not opened yet |
28
+ | llama-swap (one address for every engine) | Done as a general change: a request matching `upstream.ignorePaths` on a loaded model is served outside the scheduler (no start, no concurrency slot, no in-flight count, no ttl reset), so `/upstream/<model>/vram/lend`, `/vram/return` and `/vram/state` with `^/vram/` in `ignorePaths` reach a serving engine and never load one. Ten lines of logic, tests, docs. See [docs/llama-swap.md](docs/llama-swap.md) | Fork branch: <https://github.com/TacoTakumi/llama-swap/tree/untracked-paths>, on [mostlygeek/llama-swap](https://github.com/mostlygeek/llama-swap) 6c855da (v267). Upstream issue: [#1135](https://github.com/mostlygeek/llama-swap/issues/1135), existing. Upstream PR: not opened yet. Replaces the earlier `vram-route` branch (a `/vram` route on llama-swap's own port, routed by card) |
29
+ | `vram-lend` command and agent skill (borrower side) | Done: one command that finds the engine, directly or behind llama-swap, lends on the card named, runs the job and returns the lease when the job exits; a skill that teaches an agent when and how to use it. See [Agent instructions](#agent-instructions) | This repository: `src/vram_lend/`, the skill in `src/vram_lend/skills/vram-lend/`. Package `vram-lend` on PyPI |
30
+ | Berth (broker side) | Done on one GPU, as an experimental feature of the v0.4.0 pre-releases (rc.3 tested on this host: a 6.5 GiB voice borrower on an RTX 4060 Ti held by Maya, lend, grant and take back while Maya streams). Several GPUs under one lease are planned | [v0.4.0-rc.3](https://github.com/T-Crypt/berth/releases/tag/v0.4.0-rc.3), [contrib/LEND-PROTOCOL.md](https://github.com/T-Crypt/berth/blob/next/contrib/LEND-PROTOCOL.md). Design and tests: <https://github.com/T-Crypt/berth/issues/189> |
31
+
32
+ ## Results
33
+
34
+ Maya fork, final builds before and after the rebase onto upstream v1.1.27
35
+ (the results pages give the build of each row), on 2x RTX 3090, RTX 5060 Ti
36
+ and 2x RTX 4060 Ti. An 8 GiB lend on an RTX 4060 Ti while a request streams:
37
+
38
+ | Check | GLM-5.3-Flash | DeepSeek-V4.1 |
39
+ |---|---|---|
40
+ | Lend answer / driver shows the memory free | 0.36-0.41 s / 0.01-0.04 s after | 0.16-0.22 s / 0.01-0.05 s after |
41
+ | Largest token gap, lend / return | 0.40-0.45 s / 0.16-0.23 s | 0.23-0.28 s / 0.12-0.21 s |
42
+ | Return answer | 0.05-0.07 s | 0.08-0.13 s |
43
+ | 2 GiB on each GPU, other GPUs | all pass, 0 MiB change | all pass, 0 MiB change |
44
+ | Prompt rate at full lendable | 91% of the rate with nothing lent | 85-98% |
45
+ | Lendable before the lend = after the return | 10320 = 10320 MiB | 10478 = 10478 MiB |
46
+ | Decode with 8 GiB lent | within noise (52.5 / 50.8 / 52.2 and 47.7 / 48.8 / 49.3 t/s before / lent / after) | no penalty visible |
47
+
48
+ Over lendable (409), two leases on one GPU, a return while the memory is in
49
+ use (409, retry), a lend during a long prompt read, a late lease given back by
50
+ the server, and an engine restart all pass.
51
+
52
+ Strata fork, branch `vram-lend`, Swift 1.5 IQ4_XS on a layer split over the
53
+ 2x RTX 3090 (0000:01:00.0 on a 24.4 GB/s PCIe link, 0000:02:00.0 on a
54
+ 6.1 GB/s link). An 8 GiB lend on each RTX 3090 while a request streams:
55
+
56
+ | Check | 0000:01:00.0 | 0000:02:00.0 |
57
+ |---|---|---|
58
+ | Lend answer / driver shows the memory free | 0.04-0.05 s / 0.01-0.04 s after | 0.04-0.05 s / 0.01-0.02 s after |
59
+ | Largest token gap, lend / return | 0.046-0.056 s / 0.029-0.039 s | 0.053-0.055 s / 0.067-0.074 s |
60
+ | Return answer | 0.01-0.02 s | 0.02-0.03 s |
61
+ | 2 GiB on each GPU, other GPUs | all pass, 0 MiB change | all pass, 0 MiB change |
62
+ | Prompt rate at full lendable | 98.5-99.7% of the rate with nothing lent | 69-73%: Failed against the 90% target, accepted as the slow link's cost |
63
+ | Lendable before the lend = after the return | 12800 = 12800 MiB | 12288 = 12288 MiB |
64
+ | Decode with 8 GiB lent | -5.6 / -6.5% (hit rate 99.6 to 98.3%) | -11.5 / -9.5% (hit rate 99.6 to 97.2%) |
65
+
66
+ A lend during a long prompt read is answered at the next prompt chunk. Over
67
+ lendable, two leases on one GPU, a return while the memory is in use, an
68
+ engine restart, 50 lend/return cycles during streaming requests and the
69
+ quality suite with 8 GiB lent on each GPU all pass. A late lend (503) was
70
+ not reachable, because the engine answers inside the server's wait; the
71
+ server's unit tests cover that path. HIP and SYCL builds were not run.
72
+
73
+ llama.cpp fork, branch `vram-lend`, the same Swift 1.5 IQ4_XS with its MTP
74
+ draft head and vision encoder on an explicit split over all five GPUs. The
75
+ experts of 14 layers stay in host RAM behind an 8192 MiB MoE expert cache on
76
+ the RTX 5060 Ti (0000:05:00.0) and on one RTX 4060 Ti (0000:09:00.0); those
77
+ two cards lend 8112 MiB each. An 8 GiB lend on 0000:05:00.0 while a request
78
+ streams:
79
+
80
+ | Check | 0000:05:00.0 |
81
+ |---|---|
82
+ | Lend answer / driver shows the memory free | 0.04-0.05 s / at or before the answer |
83
+ | Largest token gap, lend / return | 0.11 s / 0.11-0.12 s |
84
+ | Return answer | 0.03-0.10 s |
85
+ | 2 GiB on each lending GPU, other GPUs | all pass, 0 MiB change |
86
+ | Prompt rate at full lendable | 101% of the rate with nothing lent (the prompt path reads host experts directly) |
87
+ | Lendable before the lend = after the return | 8112 = 8112 MiB, 20 cycles |
88
+ | Decode with 8 GiB lent | 25.0 t/s against 58.3 t/s (the host-expert rate: a full lend leaves each expert group its floor only); back within 5% on the first 300-token run after the return |
89
+
90
+ Over lendable, two leases on one GPU, a return while the memory is in use
91
+ (409, retry), a lend during a 63k-token prompt read (answered at the next
92
+ batch, 1.2-1.4 s), a late lend (503 with a 1 ms wait), an engine restart,
93
+ and the quality suite (coding 16/16, math 12/12, needles 6/6 at 32k and 128k
94
+ with both cards fully lent) all pass. Three lend cycles under the CUDA memory
95
+ checker: 0 errors. The lend-ready layout itself costs 36% of the prompt rate
96
+ against the plain split (18 GiB of experts read from host RAM) and nothing
97
+ on decode. HIP and SYCL builds were not run. The full tables are in
98
+ [bench/results/](bench/results/).
99
+
100
+ ## Agent instructions
101
+
102
+ An agent that needs GPU memory for a short job on a machine where a model is
103
+ served - an Android emulator with `-gpu host`, a speech or image service, a
104
+ small test model, a bench - can lend it from the engine with the `vram-lend`
105
+ command instead of stopping the model. The engine keeps serving, a little
106
+ slower, until the lease is returned.
107
+
108
+ Install the command and the skill:
109
+
110
+ ```
111
+ pipx install vram-lend # or: pip install vram-lend
112
+ vram-lend skills install # the skill, into every agent harness on the machine
113
+ ```
114
+
115
+ `skills install` finds Claude Code, pi, Hermes and opencode and copies the
116
+ skill into each one's user skills directory (`--scope project` for the
117
+ current repository only, `--harness NAME` for one harness). `skills status`
118
+ and `skills update` keep it current. The skill tells the agent to find the
119
+ card, read `vram-lend state`, run the job under `vram-lend run`, and what
120
+ each refusal means. It also tells it what it must never do: start, swap or
121
+ restart a model, guess ports, or use memory after a refusal.
122
+
123
+ The command itself is one Python file with no dependencies outside the
124
+ standard library, `src/vram_lend/lend.py`. Without pip, copy it onto PATH as
125
+ `vram-lend` and copy `src/vram_lend/skills/vram-lend/` into the harness's
126
+ skills directory by hand (`/home/you/.claude/skills/` for Claude Code,
127
+ `/home/you/.pi/agent/skills/` for pi).
128
+
129
+ One run, with the default server `http://127.0.0.1:8080` (llama-swap) and
130
+ the job on the first RTX 4060 Ti:
131
+
132
+ ```
133
+ vram-lend state
134
+ vram-lend run --gpu 0000:09:00.0 --mib 2048 emulator -avd Pixel_8 -gpu host
135
+ ```
136
+
137
+ `run` lends 2048 MiB on that card from whichever serving engine lists it,
138
+ starts the emulator with the lease in its environment, and returns the lease
139
+ when the emulator exits, also on a signal. For a job that is stopped later,
140
+ `vram-lend lend` prints the lease and `vram-lend return --id <id> --endpoint
141
+ <endpoint>` gives it back. `--server URL` or `VRAM_LEND_SERVER` names an
142
+ engine port or another llama-swap; `VRAM_LEND_API_KEY` carries llama-swap's
143
+ key. The verbs mirror
144
+ the HTTP API in [docs/api.md](docs/api.md), and the skill itself is at
145
+ [src/vram_lend/skills/vram-lend/SKILL.md](src/vram_lend/skills/vram-lend/SKILL.md).
146
+
147
+ ## Documentation
148
+
149
+ - [docs/api.md](docs/api.md): the HTTP API (`/vram/lend`, `/vram/return`,
150
+ `/vram/state`), status codes and lease rules.
151
+ - [docs/llama-swap.md](docs/llama-swap.md): the same API through
152
+ llama-swap's `/upstream/<model>/` passthrough for every engine it runs:
153
+ the `ignorePaths` entry, what a call does on a loaded and an unloaded
154
+ model, the fork branch that keeps a call outside the scheduler, the Berth
155
+ `lend_url`, status codes and common failures.
156
+ - [docs/engine-protocol.md](docs/engine-protocol.md): the control lines
157
+ between the server and the engine (`LEND`, `RETURN`, `LENDABLE`), when the
158
+ engine answers, answer order and late leases.
159
+ - [docs/implementing.md](docs/implementing.md): how to add VRAM Lend to an
160
+ engine: the VMM pool, the order before an unmap, the lendable rule, and the
161
+ lessons from the defects found.
162
+ - [docs/research/findings.md](docs/research/findings.md): prior art, where
163
+ the memory is, what a lend costs, and why the memory must go back to the
164
+ driver. Also [glossary.md](docs/research/glossary.md) and
165
+ [questions.md](docs/research/questions.md).
166
+ - [bench/README.md](bench/README.md): the scripts behind the results.
167
+
168
+ ## Licence
169
+
170
+ MIT, see [LICENSE](LICENSE). The Maya fork branch keeps the licence of
171
+ Project Maya, the Strata and llama.cpp fork branches the licences of those
172
+ projects.
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "vram-lend"
7
+ version = "0.1.0"
8
+ description = "Lend yourself GPU memory from a serving inference engine, run a job, give it back"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ dependencies = [
14
+ "agentsquire>=0.5.0",
15
+ ]
16
+ keywords = ["gpu", "vram", "llama.cpp", "llama-swap", "agent", "skill"]
17
+ classifiers = [
18
+ "Programming Language :: Python :: 3",
19
+ "Operating System :: POSIX :: Linux",
20
+ "Environment :: Console",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/TacoTakumi/vram-lend"
25
+
26
+ [project.scripts]
27
+ vram-lend = "vram_lend.cli:main"
28
+
29
+ # Mark vram_lend as a skill-carrying package (AgentSquire marker group). The key
30
+ # and value are the importable package name. Nothing reads this today.
31
+ [project.entry-points.'agentsquire.skills']
32
+ vram_lend = "vram_lend"
33
+
34
+ [tool.hatch.build.targets.wheel]
35
+ packages = ["src/vram_lend"]
36
+
37
+ [tool.hatch.build.targets.sdist]
38
+ only-include = ["src", "tests", "README.md", "LICENSE", "pyproject.toml"]
39
+
40
+ [dependency-groups]
41
+ dev = [
42
+ "pytest>=8.0",
43
+ ]
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ """vram-lend: lend yourself GPU memory from a serving inference engine."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,41 @@
1
+ """Console-script entry for vram-lend.
2
+
3
+ The lend verbs live in lend.py, which imports only the standard library so the
4
+ file also runs on its own. This module adds the one verb that needs a
5
+ dependency: ``skills``, AgentSquire's install/status/update/uninstall group.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
11
+
12
+ from . import lend
13
+
14
+
15
+ def main(argv: list[str] | None = None) -> int:
16
+ args = list(sys.argv[1:] if argv is None else argv)
17
+ _notice_stale_skill()
18
+ if args and args[0] == "skills":
19
+ from agentsquire.cli import skills_command_group
20
+
21
+ group = skills_command_group("vram_lend", default_scope="user")
22
+ return group.main(args=args[1:], prog_name="vram-lend skills",
23
+ standalone_mode=False) or 0
24
+ return lend.main(args)
25
+
26
+
27
+ def _notice_stale_skill() -> None:
28
+ """One advisory line on stderr when an installed copy of the skill is
29
+ older than the shipped one. Never prompts, never updates, never changes
30
+ the exit code; CI or AGENTSQUIRE_NO_UPDATE_CHECK silence it."""
31
+ try:
32
+ from agentsquire import BundledPackageDataSource, check_stale
33
+
34
+ check_stale(BundledPackageDataSource("vram_lend"), prog_name="vram-lend",
35
+ update_command="vram-lend skills update")
36
+ except Exception:
37
+ pass
38
+
39
+
40
+ if __name__ == "__main__":
41
+ sys.exit(main())