客户端与服务端必须同时支持 zstd,仅支持 LZ4 的旧版本会被直接拒绝,需一起升级;客户端镜像不含 CUDA/ROCm SDK,程序要自带 CUDA 运行时和库;跨服务器直连传输、跨服务器 peer access 和 cuMemcpy3DPeer 尚未实现。
lupine
lupinemachinesApache-2.0活跃维护把远程机器上的 GPU 通过 IP 网络桥接给只有 CPU 的机器使用,让无显卡设备也能跑 CUDA 计算和推理任务。
LUPINE is a GPU over IP bridge allowing GPUs on remote machines to be attached to CPU-only machines.
docker run --rm --gpus all -p 14833:14833 ghcr.io/lupinemachines/lupine-server:cuda-13.3.1-ubuntu24.04
docker run --rm -it -e LUPINE_SERVER=<server>:14833 ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04 nvidia-smi服务端需在带 GPU 的机器上运行,示例用 --gpus all 挂载 NVIDIA 显卡(实测 RTX 4090);服务端镜像在 amd64 上还装了 ROCm HIP 运行时以支持 AMD GPU;客户端为纯 CPU 机器,Linux 客户端要求 glibc 2.28 以上。README 未说明显存要求。
把远程机器的 GPU 通过 IP 挂到无 GPU 的机器上,让 CUDA 程序像本地显卡一样跑
把远程机器上的 GPU 通过 IP 网络桥接给只有 CPU 的机器使用,让无显卡设备也能跑 CUDA 计算和推理任务。
核心能力
- 用 libcuda.so.1 与 NVML shim 把驱动调用转发到远端 GPU
- 客户端容器内自动设置 LD_LIBRARY_PATH 加载 shim
- 支持逗号分隔多服务器,按顺序合并为本地设备列表
- 跨服务器 DtoD/Peer 拷贝经客户端中转实现
- RPC 体强制 zstd 压缩,并启用 TCP keepalive 保活
容易踩的坑
- v2.1.0Lupine 2.1.0最新正式版2026-10-13 · 2026-10-13 01:16 UTC
Lupine 2.1.0 adds an ARM64 macOS PyTorch backend using converted NVIDIA SDK libraries and packaged PyTorch CUDA operators. Tensor metadata and autograd stay in native macOS PyTorch, while GPU work runs through the Lupine driver client on a remote NVIDIA GPU. This replaces the Mac container/torch-worker backend.
The backend queues work on the default CUDA stream, uses the packaged ATen caching allocator, and avoids redundant transfers and metadata queries. At matched network latency, the tested FP32 arithmetic, matrix multiplication, training, and layer-normalization workloads meet or exceed the remote Linux client timings.
The initial native Mac backend supports one GPU, float32 arithmetic, int64 transfers/fill/arange, matrix multiplication, layer normalization, 2D convolution, softmax, associated gradients, and math attention. Unsupported operators raise; mixed precision, fused attention, CUDA graphs, and torch.compile are not supported yet. Linux and Windows continue to use CUDA PyTorch with the native driver client.
Both
lupineandlupine-autoare version 2.1.0. The ARM64 Mac wheel packages the CUDA SDK and operator dylibs. Driver and NVML dylibs are fetched separately from the selected server to match its wire protocol. Preparation, native linking, and signing are separate build stages.The Mac runtime wheel is distributed in 1-GiB release asset parts. Download its
.whl.part*files andmacos-wheel-SHA256SUMS, concatenate the parts in filename order, verify withshasum -a 256 -c macos-wheel-SHA256SUMS, and install the reconstructed wheel with pip. The universal Python wheel on PyPI provides driver support; native Mac operators require this runtime wheel on macOS 26 or newer. - v2.0.32026-09-02 · 2026-09-02 05:36 UTC
查看更新说明
What's Changed
- Fix CUDA 13.2 PyTorch runtime imports by @kevmo314 in https://github.com/lupinemachines/lupine/pull/694
- Simplify Docker image build stages by @kevmo314 in https://github.com/lupinemachines/lupine/pull/692
- Prepare Python 2.0.3 release by @kevmo314 in https://github.com/lupinemachines/lupine/pull/695
Full Changelog: https://github.com/lupinemachines/lupine/compare/v2.0.2...v2.0.3
- v2.0.22026-09-02 · 2026-09-02 03:57 UTC
查看更新说明
What's Changed
- Separate PyPI publisher identities by @kevmo314 in https://github.com/lupinemachines/lupine/pull/688
- Serve server-selected native client bundles by @kevmo314 in https://github.com/lupinemachines/lupine/pull/689
- Ship runtime-only Python wheels with cloud auth by @kevmo314 in https://github.com/lupinemachines/lupine/pull/690
Full Changelog: https://github.com/lupinemachines/lupine/compare/v2.0.1...v2.0.2
- v2.0.12026-08-31 · 2026-08-31 09:44 UTC
查看更新说明
Coherent Python package release for the automatic cloud bootstrap.
- Publishes
lupine==2.0.1andlupine-auto==2.0.1from this exact tag. lupine[auto]pinslupine-auto==2.0.1;lupine-autopinslupine==2.0.1.- Release workflows build and publish from the resolved tag commit.
- Wire identity remains empty for this release.
- Publishes
- v2.0.02026-08-31 · 2026-08-31 08:12 UTC
查看更新说明
What's Changed
- Cache function attributes and make kernel attribute sets async by @kevmo314 in https://github.com/lupinemachines/lupine/pull/488
- Move library metadata to an explicit snapshot RPC by @kevmo314 in https://github.com/lupinemachines/lupine/pull/491
- Prefill library kernel function handles by @kevmo314 in https://github.com/lupinemachines/lupine/pull/489
- Isolate event query cache warming by @kevmo314 in https://github.com/lupinemachines/lupine/pull/499
- Add request-owned RPC writes by @kevmo314 in https://github.com/lupinemachines/lupine/pull/501
- Run custom driver-API tests in parallel with per-test servers by @kevmo314 in https://github.com/lupinemachines/lupine/pull/505
- Bypass latency caches for local CUDA routes by @kevmo314 in https://github.com/lupinemachines/lupine/pull/506
- Separate function lookup from parameter-layout prefetch by @kevmo314 in https://github.com/lupinemachines/lupine/pull/500
- Prefill function and kernel attributes by @kevmo314 in https://github.com/lupinemachines/lupine/pull/490
- Move transient RPC writes into serializers by @kevmo314 in https://github.com/lupinemachines/lupine/pull/502
- Use cached parameter layout bounds by @kevmo314 in https://github.com/lupinemachines/lupine/pull/507
- Release resources after failed client disconnects by @kevmo314 in https://github.com/lupinemachines/lupine/pull/508
- Remove redundant launch context validation by @kevmo314 in https://github.com/lupinemachines/lupine/pull/509
- Keep high-latency HTTP/2 connections warm by @kevmo314 in https://github.com/lupinemachines/lupine/pull/511
- Replace codegen requirements.txt with uv inline script metadata by @kevmo314 in https://github.com/lupinemachines/lupine/pull/514
- Limit GPU integration concurrency by @kevmo314 in https://github.com/lupinemachines/lupine/pull/521
- Preallocate RPC write buffers by @kevmo314 in https://github.com/lupinemachines/lupine/pull/510
- Centralize null remote-connection handling in rpc_write_start_request by @kevmo314 in https://github.com/lupinemachines/lupine/pull/519
- Add CUDA and NVML API coverage for vLLM by @kevmo314 in https://github.com/lupinemachines/lupine/pull/524
- Prevent destroyed CUDA events from entering query batches by @kevmo314 in https://github.com/lupinemachines/lupine/pull/526
- Translate client host UVA aliases for pointer APIs and generic copies by @kevmo314 in https://github.com/lupinemachines/lupine/pull/525
- Preserve zero-capacity present optional output arrays in graph queries by @kevmo314 in https://github.com/lupinemachines/lupine/pull/518
- Name CUDA-specific client and server sources by @kevmo314 in https://github.com/lupinemachines/lupine/pull/535
- Decouple the RPC core from CUDA by @kevmo314 in https://github.com/lupinemachines/lupine/pull/536
- Build native macOS client dylibs by @kevmo314 in https://github.com/lupinemachines/lupine/pull/549
- Enable freeImageInteropNPP, cuda-c-linking, and device-side-launch samples by @kevmo314 in https://github.com/lupinemachines/lupine/pull/545
- Share client transport across API shims by @kevmo314 in https://github.com/lupinemachines/lupine/pull/537
- Add pitched RPC read and write primitives by @kevmo314 in https://github.com/lupinemachines/lupine/pull/552
- Route server dispatch through an annotated registry by @kevmo314 in https://github.com/lupinemachines/lupine/pull/538
- Build native Windows client DLLs by @kevmo314 in https://github.com/lupinemachines/lupine/pull/550
- Split generated RPC code by backend by @kevmo314 in https://github.com/lupinemachines/lupine/pull/539
- Componentize the build by RPC core and backend by @kevmo314 in https://github.com/lupinemachines/lupine/pull/540
- Bump h2 from 4.4.0 to 4.4.1 in /python in the uv group across 1 directory by @dependabot[bot] in https://github.com/lupinemachines/lupine/pull/551
- Refactor RPC write queue to use std::vector by @kevmo314 in https://github.com/lupinemachines/lupine/pull/558
- feat: add cuStreamGetGreenCtx RPC by @kev
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
LUPINE: GPU-over-IP
LUPINE is a GPU over IP bridge allowing GPUs on remote machines to be attached to CPU-only machines.
Quick Start
Use the published GHCR images. The examples below pin CUDA 13.3.1 on
Ubuntu 24.04; other published tags use the same
cuda-<cuda-version>-ubuntu<ubuntu-version> format.
Run the server on the GPU machine:
docker run --rm --gpus all -p 14833:14833 \
ghcr.io/lupinemachines/lupine-server:cuda-13.3.1-ubuntu24.04
Run the client pointing at that server:
docker run --rm -it \
-e LUPINE_SERVER=<server>:14833 \
ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04 \
nvidia-smi
Example output from a real run against a remote RTX 4090:
Mon May 18 15:40:46 2026
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.288.01 Driver Version: 590.48.01 CUDA Version: 13.1 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce RTX 4090 On | 00000000:01:00.0 On | Off |
| 30% 52C P8 22W / 450W | 8MiB / 24564MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| No running processes found |
+---------------------------------------------------------------------------------------+
Inside the client container, LD_LIBRARY_PATH=/opt/lupine/lib is already set,
so CUDA driver users pick up the LUPINE libcuda.so.1 shim and NVML users such
as nvidia-smi pick up the LUPINE libnvidia-ml.so.1 shim automatically.
Prometheus Metrics
Linux servers built with CUDA and NVML expose Prometheus metrics on the RPC port without monitoring-specific configuration:
curl http://<server>:14833/metrics
The endpoint reports host GPU memory capacity, memory use and utilization,
plus memory and utilization for each connected client process. It also exports
the mapping between client identity, the Lupine connection child, and the host
PID reported by NVML. Values are collected when /metrics is requested, so
the server does no background NVML polling.
Client compatibility
Each production server executable embeds the matching Linux, macOS, and
Windows client objects for amd64 and arm64; there is no client-bundle directory
to deploy beside it. A bundle carries libcuda.so.1
/ libcuda.dylib / nvcuda.dll, NVML, and on Linux the NCCL and nvSHMEM
shims, which cannot work through the driver by itself. Programs run their own
CUDA runtime and libraries against it, so only driver calls cross the wire.
Python clients fetch the current object from
/.well-known/lupine/client/v1/<os>/<arch>, verify its strong ETag, content
digest, manifest, and file hashes, and cache it locally. The selected ETag is
also asserted when the RPC connection opens, closing the race between
discovery and a server upgrade. LUPINE_LIBDIR remains an explicit local
override for development.
Linux client objects target the manylinux_2_28 ABI (glibc 2.28) and statically include their private C++, HTTP/2, and TLS dependencies. They therefore work on newer glibc distributions, including Ubuntu 22.04, without requiring host copies of libstdc++, nghttp2, or OpenSSL. Linux clients require glibc 2.28 or newer; CentOS/RHEL 7 and Ubuntu 18.04 are no longer supported.
Graceful Server Checkpoints
On Linux, SIGTERM stops the server from accepting connections, asks every
connection child to finish its in-flight CUDA calls, and waits for those
children to exit. This graceful drain happens in the open-source server with
no extra runtime dependency.
Each connection child looks for liblupinecr.so.0, then liblupinecr.so, and
uses the versioned provider ABI in
checkpoint_provider.h. A missing or incompatible
provider is a no-op; the server still drains and exits normally. The provider
is loaded before the child's first CUDA call so it can observe RM/UVM activity
needed to discover allocations.
Set LUPINE_SESSION in the client to attach a stable connection identifier.
The optional provider receives that identifier to restore the connection
before its first CUDA RPC and checkpoint it after shutdown has drained. For an
unkeyed connection, restore is skipped and checkpoint receives a null
identifier. Providers own storage configuration, file layout, and any fallback
policy for unkeyed connections; Lupine does not select a checkpoint directory.
LUPINE_CHECKPOINT_LIBRARY can override the provider library path for a
private deployment.
Connection Stability
Each client/server connection is a single long-lived TCP stream. Long-running workloads sit idle for long stretches (between training steps, during host-side data loading, inside long kernels), and stateful middleboxes — cloud load balancers, NAT gateways, conntrack tables, firewalls — silently reap idle flows far sooner than the kernel's default 2-hour keepalive. The next RPC then fails fatally. Lupine keeps these connections alive and resilient without retrying RPCs (which would break CUDA semantics):
RPC request and response bodies require content-encoding: zstd. Compression
is applied transparently at level -1, using one streaming Zstd frame per HTTP/2
body and a 512 KiB history window. RPC boundaries flush the stream without
resetting its history. No compression setting is needed. Clients and servers
must both support Zstd; older LZ4-only peers are rejected rather than falling
back to another encoding. Upgrade the client and server together.
- TCP keepalive is enabled on every connection (client and server) with a 60s idle interval, 15s between probes, and 3 unanswered probes before giving up. Probes are sent only while idle, so active transfers pay no latency cost, and a dead peer is detected in ~105s instead of hanging on the TCP retransmit timer.
- Connect retry rides out a server that is not reachable yet (e.g. still provisioning): a connection is attempted a few times with exponential backoff, and each attempt is bounded by a deadline so a packet-filtered port is detected quickly rather than blocking for the full SYN-retransmit window.
Socket buffer sizes are left to the OS, which auto-tunes on modern kernels.
Trace Logging
Set LUPINE_TRACE on the client, server, or both to enable trace logging.
LUPINE_TRACE=0 or an unset value disables tracing. LUPINE_TRACE=1 writes
trace output to stdout, LUPINE_TRACE=2 writes it to stderr, and any other
non-empty value is treated as a file path opened in append mode.
# trace to stdout
LUPINE_TRACE=1 ./your_cuda_program
# trace to stderr
LUPINE_TRACE=2 ./server
# trace to a file
LUPINE_TRACE=/tmp/lupine.trace ./your_cuda_program
The same LUPINE_TRACE variable controls both client and server tracing;
LUPINE_SERVER_TRACE is no longer used.
Device printf Forwarding
LUPINE inspects uploaded PTX and cubin symbol data for vprintf, the CUDA device
printf implementation. Until an image that may use device stdout is loaded,
synchronization avoids stdout redirection and its process-global lock, allowing
independent RPC lanes to synchronize concurrently. Fully opaque compressed
fatbins are treated conservatively as potentially using device stdout.
After a device-output-capable image is loaded, context, stream, and event
synchronization captures server fd 1 and forwards the bounded CUDA printf
buffer to the client's stdout. Capture remains process-global so output from
concurrent synchronization lanes is not misattributed.
Multi-GPU Across Multiple Servers
The client accepts a comma-separated LUPINE_SERVER list. Devices are exposed as
one local ordinal list in server order: all GPUs from the first server, then all
GPUs from the next server, and so on.
Run a server on each GPU machine:
# on gpu-host-a
docker run --rm --gpus all -p 14833:14833 \
ghcr.io/lupinemachines/lupine-server:cuda-13.3.1-ubuntu24.04
# on gpu-host-b
docker run --rm --gpus all -p 14833:14833 \
ghcr.io/lupinemachines/lupine-server:cuda-13.3.1-ubuntu24.04
Point the client at both servers:
docker run --rm --network host \
-e LUPINE_SERVER=gpu-host-a:14833,gpu-host-b:14833 \
ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04 \
nvidia-smi -L
Expected output lists both remote GPUs:
GPU 0: NVIDIA GeForce RTX 4090 (UUID: GPU-...)
GPU 1: NVIDIA GeForce RTX 4090 (UUID: GPU-...)
CUDA driver applications use the same LUPINE_SERVER value:
docker run --rm --network host \
-e LUPINE_SERVER=gpu-host-a:14833,gpu-host-b:14833 \
ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04 \
./your_cuda_program
Cross-server device-to-device and peer (cuMemcpyDtoD / cuMemcpyPeer) copies are
supported: when the source and destination live on different servers, the client
transparently stages the data through itself (device->host on one server, then
host->device on the other). Direct server-to-server transfers that avoid that
client hop, cross-server peer-access enablement, and cuMemcpy3DPeer are not
implemented yet.
Same-server operations route by handle ownership.
Prefix an endpoint with https:// when the Lupine server is behind a
TLS-terminating proxy. Both CUDA applications and NVML tools such as
nvidia-smi use the scheme and verify the proxy certificate against the
system trust store. HTTPS defaults to port 443; plain and http:// endpoints
default to port 14833.
For a specific CUDA version:
docker pull ghcr.io/lupinemachines/lupine-client:cuda-12.4.1-ubuntu22.04
docker pull ghcr.io/lupinemachines/lupine-server:cuda-12.4.1-ubuntu22.04
Client images contain the CUDA driver, NCCL, nvSHMEM, NVML, and HIP shims,
their runtime dependencies, and nvidia-smi. Programs bring their own CUDA
runtime and libraries. They are based on Ubuntu and contain neither the CUDA
nor ROCm SDK. The -slim tags remain available as compatibility aliases with the same
SDK-free contents, for example
ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04-slim.
The server image is also based on Ubuntu. It installs the CUDA compatibility runtime and, on amd64, the ROCm HIP runtime so one image can serve either NVIDIA or AMD GPUs; the older separate HIP server Dockerfile is no longer needed.
Slow Start for the Skeptics
This path derives a small PyTorch client image from the published LUPINE client
image and runs the microgpt_train test against a remote GPU. It is
intentionally explicit so it is easy to see which side is the CPU-only client
and which side owns the GPU.
Create a PyTorch client Dockerfile in the repo root:
# Dockerfile.pytorch-lupine
FROM ghcr.io/lupinemachines/lupine-client:cuda-13.3.1-ubuntu24.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --break-system-packages \
--index-url https://download.pytorch.org/whl/cu132 \
torch
COPY test/pytorch_lupine_tests.py /opt/lupine/test/pytorch_lupine_tests.py
ENV LD_LIBRARY_PATH=/opt/lupine/lib:${LD_LIBRARY_PATH}
CMD ["python3", "/opt/lupine/test/pytorch_lupine_tests.py", "microgpt_train"]
Build it:
docker build -f Dockerfile.pytorch-lupine -t lupine-pytorch:cuda-13.3 .
Run the server on the GPU machine:
docker run --rm --gpus all -p 14833:14833 \
ghcr.io/lupinemachines/lupine-server:cuda-13.3.1-ubuntu24.04
Run the PyTorch client from the CPU-only machine:
docker run --rm \
-e LUPINE_SERVER=<server>:14833 \
lupine-pytorch:cuda-13.3
Expected success looks like:
microgpt first_loss=... last_loss=...
microgpt_train: PASS
Local development
Building the binaries requires running codegen first. The repository provides a containerized runner so local development and CI use the same CUDA and HIP headers, Python, parser, and formatter versions. Docker is the only host dependency.
Run codegen
./codegen/run.sh
Ensure there are no errors in the output of the codegen.
Run cmake
cmake -S . -B build
cmake --build build
CMake builds the CUDA driver shim at build/libcuda.so.1, the NCCL shim at
build/libnccl.so.2 on Linux (when NCCL 2.14.3 or newer headers are found
beside the toolkit's or through -DLUPINE_NCCL_INCLUDE_DIR=<dir>), the nvSHMEM
shim at build/libnvshmem_host.so.3 on Linux (when nvSHMEM 3 headers carrying
nvshmem_host.h are found beside the toolkit's or through
-DLUPINE_NVSHMEM_INCLUDE_DIR=<dir>), the NVML shim at
build/libnvidia-ml.so.1, the HIP shim at build/libamdhip64.so.1, and the
server at build/lupine_driver_server. A program runs against NVIDIA's own
CUDA runtime and libraries on the client; the driver shim forwards the cu*
calls they make, and the NCCL shim forwards nccl* calls on the driver shim's
connections, so the two must come from the same build. The server loads the
machine's libnccl.so.2 by name.
nvSHMEM is the exception: it forwards nothing at all.
Its PEs hold a partitioned global address space over the GPUs of a job, reading
and writing each other's symmetric heap from inside kernels, and a client is
not one of them. The process that owns a GPU here is the server, which serves
many clients at once, while nvSHMEM keeps its PE identity, its symmetric heap
and its teams in process-global state with no handle to tell one job from
another; its heap sits outside the identity VA arena a client reserves; and its
device half never reaches a host shim. So the shim loads, answers the version
and status queries truthfully, and refuses everything else -
nvshmemid_hostlib_init_attr with NVSHMEMX_ERROR_NOT_SUPPORTED, the
allocators and peer pointers with null, the collectives with an error - rather
than return a value it cannot mean. That is enough for PyTorch, whose
libtorch_cuda.so reaches libnvshmem_host.so.3 through libtorch_nvshmem.so
in its NEEDED and never calls it unless a program asks for symmetric memory.
A communicator whose ranks sit behind different servers needs those servers to
reach each other: NCCL's bootstrap and transport run between the server
processes, so settings such as NCCL_SOCKET_IFNAME belong in each server's
environment. Drive such ranks from a thread each, as separate processes would;
a group reaching two servers from one thread returns ncclInvalidUsage.
Redistributable server builds pass LUPINE_CLIENT_BUNDLE_INPUT with staged
native client directories, one lupine-client-<tag> per platform holding the
driver and NVML shims and, on Linux, the NCCL and nvSHMEM shims. CMake
deterministically assembles all six platform routes from those files alone and
links them into lupine_driver_server. The Docker server target requires
that generated registry, so a server image cannot be produced without the
clients.
The Lupine server must be running before initiating client commands.
./local.sh server
If successful, the server will start:
Server listening on port 14833...
Running the client
For local development, preload the built libcuda.so.1 before executing CUDA
commands. The published client image sets LD_LIBRARY_PATH for you instead.
Once the server above is running:
# update to your desired IP/port
export LUPINE_SERVER=<server>:14833
LD_PRELOAD=./build/libcuda.so.1 python3 -c "import torch; print(torch.cuda.is_available())"
# or
LD_PRELOAD=./build/libcuda.so.1 nvidia-smi
You can also use the local shell script to run your commands.
./local.sh run
The opt-in HIP / ROCm test runners build and run upstream hip-tests, rocm-examples, and rocBLAS/hipBLAS clients locally or against an SSH server. They include native baseline runs and a separate CTest project; AMD hardware tests are not enabled in CI.
Questions
- What does LUPINE stand for? Nothing, it just looks cool in all caps.
- Does this support authentication? TLS? Indirectly, yes. It's a plain HTTP/2 server, so you can front it with whatever TLS/auth server you want.
- Was this repo AI-generated? A chunk of it, yes. I mean, would you want to hand write hundreds of tedious API stubs? No? Me neither.
- Doesn't this incur a lot of latency? Surprisingly, no! You will see device transfers get slower because this is basically bottlenecking a PCIe link over the network, but there is very little overhead besides that. For things like model training and inference, once the model is on the GPU very little data transfer happens to the host. As a result, it might be faster than you expect.
- Can I do remote video encoding/decoding? This is probably one use case we wouldn't recommend because that's a lot heavier on the PCIe link. It works in theory though, so if you do have access to a 1 Tbps link it might work for you.
Prior Art
This project is inspired by some existing proprietary solutions:
Optional client id
client_id on the monitoring metrics is the client process id. Set
LUPINE_WORKLOAD_ID to use that value instead, for example job-123:worker-0.
Lupine does not interpret it. Processes that report the same value, from the
same address and hostname and with the same process name, share one series for
a device. client_pid on lupine_server_connection_info stays the process id
either way. The value is attribution metadata, not an authentication credential.
The identifier must be valid UTF-8 and at most 256 bytes. Empty means unset; invalid values are ignored without truncation or disrupting GPU calls. Clients read it when establishing each connection, including reconnects. The existing metadata version is unchanged: the value is an optional trailing extension. Older servers ignore it; newer servers treat metadata from older clients as unset and keep the process id.
lupine_server_connection_info, lupine_client_device_memory_used_bytes and
lupine_client_device_utilization_percent carry this client_id. Connections
from the same client process that report different values keep the process id.
Disconnecting removes the value with its connection registry entry.