Script assisted by Claude
This commit is contained in:
+118
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
gpu_keepalive.py
|
||||
|
||||
Tiny AMD GPU keep-alive utility for Windows/WDDM VRAM eviction issues
|
||||
(e.g. llama.cpp / llama-server on RX 7900 XTX + Adrenalin drivers).
|
||||
|
||||
What it does:
|
||||
- Opens an OpenCL context on the AMD GPU
|
||||
- Allocates a small buffer resident in GPU memory
|
||||
- Runs a trivial kernel against it on a timer
|
||||
- This keeps the GPU context "active" so the driver's idle
|
||||
power-management / residency-trim path doesn't decide to
|
||||
evict allocations to system RAM.
|
||||
|
||||
This does NOT touch llama.cpp or llama-server directly. It just
|
||||
keeps the card from ever reaching the idle state that triggers
|
||||
eviction, so llama-server's own VRAM allocation is less likely
|
||||
to get trimmed.
|
||||
|
||||
Requirements:
|
||||
pip install pyopencl
|
||||
|
||||
Usage:
|
||||
python gpu_keepalive.py # defaults: 4s interval, 64MB buffer
|
||||
python gpu_keepalive.py --interval 3 --size-mb 128
|
||||
python gpu_keepalive.py --list # list available OpenCL devices
|
||||
|
||||
Stop with Ctrl+C.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import pyopencl as cl
|
||||
import numpy as np
|
||||
except ImportError:
|
||||
print("Missing dependencies. Install with:\n pip install pyopencl numpy")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
KERNEL_SRC = """
|
||||
__kernel void touch(__global float* buf) {
|
||||
int i = get_global_id(0);
|
||||
buf[i] = buf[i] + 1.0f;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def find_amd_device():
|
||||
for platform in cl.get_platforms():
|
||||
for device in platform.get_devices():
|
||||
if device.type & cl.device_type.GPU and "amd" in (platform.name + device.name).lower():
|
||||
return platform, device
|
||||
# fallback: just grab the first GPU device found
|
||||
for platform in cl.get_platforms():
|
||||
for device in platform.get_devices():
|
||||
if device.type & cl.device_type.GPU:
|
||||
return platform, device
|
||||
return None, None
|
||||
|
||||
|
||||
def list_devices():
|
||||
for platform in cl.get_platforms():
|
||||
print(f"Platform: {platform.name}")
|
||||
for device in platform.get_devices():
|
||||
print(f" Device: {device.name} ({device.type})")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Tiny AMD GPU keep-alive to prevent WDDM VRAM eviction.")
|
||||
parser.add_argument("--interval", type=float, default=4.0, help="Seconds between GPU touches (default: 4)")
|
||||
parser.add_argument("--size-mb", type=int, default=64, help="Size of the resident buffer in MB (default: 64)")
|
||||
parser.add_argument("--list", action="store_true", help="List OpenCL platforms/devices and exit")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list:
|
||||
list_devices()
|
||||
return
|
||||
|
||||
platform, device = find_amd_device()
|
||||
if device is None:
|
||||
print("No OpenCL GPU device found. Is the AMD OpenCL runtime installed (it ships with Adrenalin)?")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Using platform: {platform.name}")
|
||||
print(f"Using device: {device.name}")
|
||||
|
||||
ctx = cl.Context([device])
|
||||
queue = cl.CommandQueue(ctx)
|
||||
program = cl.Program(ctx, KERNEL_SRC).build()
|
||||
kernel = cl.Kernel(program, "touch")
|
||||
|
||||
n_floats = (args.size_mb * 1024 * 1024) // 4
|
||||
host_buf = np.zeros(n_floats, dtype=np.float32)
|
||||
mf = cl.mem_flags
|
||||
gpu_buf = cl.Buffer(ctx, mf.READ_WRITE | mf.COPY_HOST_PTR, hostbuf=host_buf)
|
||||
|
||||
print(f"Resident buffer: {args.size_mb} MB")
|
||||
print(f"Touch interval: {args.interval}s")
|
||||
print("Running. Ctrl+C to stop.\n")
|
||||
|
||||
try:
|
||||
tick = 0
|
||||
while True:
|
||||
kernel.set_args(gpu_buf)
|
||||
cl.enqueue_nd_range_kernel(queue, kernel, (n_floats,), None)
|
||||
queue.finish()
|
||||
tick += 1
|
||||
print(f"\r[keep-alive] touched GPU buffer #{tick}", end="", flush=True)
|
||||
time.sleep(args.interval)
|
||||
except KeyboardInterrupt:
|
||||
print("\nStopped.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user