Library / SDK
lupinemachines/lupine avatar
lupinemachines/lupine

LUPINE: Attaching Remote GPUs to CPU-Only Machines Over TCP

LUPINE is a GPU over IP bridge allowing GPUs on remote machines to be attached to CPU-only machines.

2,427 stars135 forksC++Apache-2.0

At a glance

What is it?
LUPINE is an Apache-2.0 C++ bridge that exposes GPUs on remote servers as local CUDA devices, with a shim library and a long-lived TCP connection. It is useful for developers who need GPU acceleration on machines that lack one.
Who is it for?
Adopt LUPINE if you need occasional GPU access on a CPU-only machine, especially for development or testing, and you can tolerate the network overhead and the single-connection model. Do not use it for latency-sensitive HPC workloads or where you need to rely on a stable internet connection without keepalive support.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What LUPINE Solves and Who It Is For

The project is written in C++ and released under Apache-2.0. The repository shows recent releases, with v1.0.0 published in August 2026. The documentation is detailed, covering connection stability and checkpointing, which suggests a mature design. But you should not confuse maturity with performance. The overhead of network RPCs is real, and the README does not pretend otherwise.

The Shimming Mechanism: How CUDA Calls Cross the Wire

The transport is a single long-lived TCP stream per connection. That design choice has consequences, which the project addresses with a whole section on connection stability. The README explains that stateful middleboxes like cloud load balancers and NAT gateways silently reap idle flows, which would kill a long-running workload. LUPINE enables TCP keepalive with specific parameters: 60-second idle interval, 15-second probe interval, and 3 probes before giving up. This means a dead peer is detected in about 105 seconds. There is also connect retry with exponential backoff for when the server is not reachable yet. These are not afterthoughts; they are the difference between a tool that works on a LAN and one that works across the internet.

Getting Started: The Docker Quick Start Path

There is also a hosted demo. You can run a client container pointing at demo.lupinemachines.com:14833 and get a T4 GPU. The README warns that initial provisioning might take a while if no GPU is currently allocated. This is a low-friction way to test the concept without setting up your own server. For the Mac demo, you run a Python script with uv, and it prompts for the server IP and port. The output shows a tensor operation returning results, confirming CUDA is available. The configuration is minimal: the client reads LUPINE_SERVER, and you can pass a comma-separated list for multiple servers. That is the entire setup. No kernel modules, no special privileges on the client, just a container.

Multi-GPU and Device Ordering: A Simple Model with Limits

The client supports multiple servers via 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 from the next. This is straightforward, but it has a limitation. You cannot mix or reorder GPUs arbitrarily. If you need a specific device mapping, you have to order the server list yourself. The README does not mention any way to select a specific GPU from a server; it assumes all GPUs on a server are exposed. This is fine for a single-GPU server, but on a multi-GPU machine, you get all of them, which might not be what you want. The documentation does not say whether you can limit the server to a subset of GPUs, so you should assume you cannot. This is a real constraint for users with heterogeneous GPU setups.

Graceful Checkpoints: A Provider-Based Extension

A notable feature is graceful server checkpoints. On Linux, when the server receives SIGTERM, it stops accepting new connections, asks existing connection children to finish in-flight CUDA calls, and waits for them to exit. This is a clean shutdown, but the interesting part is the checkpoint provider. Each connection child looks for liblupinecr.so.0, then liblupinecr.so, and uses a versioned provider ABI defined in checkpoint_provider.h. The provider can observe RM/UVM activity to discover allocations, restore a connection before its first CUDA RPC, and checkpoint after shutdown. The README is clear that the provider is optional; a missing or incompatible provider is a no-op. You can set LUPINE_SESSION on the client to attach a stable connection identifier, which the provider uses to restore and checkpoint. The server does not select a checkpoint directory; the provider owns that. This is a well-designed extension point, but it is also a warning: if you want checkpointing, you have to write or find a provider yourself. The open-source server includes the drain logic, but the actual persistence is your problem. The LUPINE_CHECKPOINT_LIBRARY environment variable lets you override the provider path, which is useful for private deployments.

Device printf Forwarding and Trace Logging: The Details That Matter

Trace logging is controlled by a single environment variable, LUPINE_TRACE, on both client and server. LUPINE_TRACE=1 writes to stdout, LUPINE_TRACE=2 to stderr, and any other non-empty value is treated as a file path in append mode. The README notes that LUPINE_SERVER_TRACE is no longer used, so you only need to set one variable. This is a simple debugging aid, but it shows the project's attention to operational details.

Limitations, Alternatives, and What to Verify

An alternative approach is to use a remote desktop or a GPU-sharing framework like NVIDIA's vGPU or MPS, but those require virtualization or driver support. Another alternative is to simply run your workload on the GPU machine via SSH or a job scheduler, which avoids the network overhead entirely. The difference is that LUPINE gives you a local CUDA device, which is convenient for interactive development, but it does not give you the performance of a local GPU. You should also verify the CUDA version compatibility. The README pins CUDA 13.3.1 for the images, but your application might require a different version. The shim intercepts the driver API, so the CUDA runtime version on the client must be compatible with the shim. The documentation does not specify the supported range, so you need to test. Finally, check the license implications. Apache-2.0 is permissive, but if you use the checkpoint provider ABI, you are writing code against a header, which is fine. No legal advice here, but you should read the license if you distribute modifications.

Editorial conclusion

Adopt LUPINE if you need occasional GPU access on a CPU-only machine, especially for development or testing, and you can tolerate the network overhead and the single-connection model. Do not use it for latency-sensitive HPC workloads or where you need to rely on a stable internet connection without keepalive support. Before adopting, verify the CUDA version compatibility with your workloads, test the connection stability on your network, and confirm that the graceful checkpoint provider, if needed, is available for your use case.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community notes

Community notes