Packages
snakepit
0.8.3
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
High-performance pooler and session manager for external language integrations. Supports Python, Node.js, Ruby, and more with gRPC streaming, session management, and production-ready process cleanup.
Current section
Files
Jump to
Current section
Files
lib/snakepit/hardware/selector.ex
defmodule Snakepit.Hardware.Selector do
@moduledoc """
Device selection logic for hardware abstraction.
Provides intelligent device selection based on availability, preferences,
and fallback strategies.
"""
alias Snakepit.Hardware.Detector
@type device ::
:cpu
| :cuda
| :mps
| :rocm
| {:cuda, non_neg_integer()}
| {:rocm, non_neg_integer()}
@type device_preference :: :auto | :cpu | :cuda | :mps | :rocm | {:cuda, non_neg_integer()}
@doc """
Selects a device based on preference.
## Options
- `:auto` - Automatically select the best available accelerator
- `:cpu` - Select CPU (always available)
- `:cuda` - Select CUDA (fails if not available)
- `:mps` - Select MPS (fails if not available or not on macOS)
- `:rocm` - Select ROCm (fails if not available)
- `{:cuda, device_id}` - Select specific CUDA device
## Returns
- `{:ok, device}` on success
- `{:error, :device_not_available}` if requested device is unavailable
"""
@spec select(device_preference()) :: {:ok, device()} | {:error, :device_not_available}
def select(:auto) do
info = Detector.detect()
device =
cond do
info.cuda != nil and info.cuda.devices != [] ->
{:cuda, 0}
info.mps != nil and info.mps.available ->
:mps
info.rocm != nil and info.rocm.devices != [] ->
{:rocm, 0}
true ->
:cpu
end
{:ok, device}
end
def select(:cpu) do
{:ok, :cpu}
end
def select(:cuda) do
info = Detector.detect()
case info.cuda do
%{devices: [_ | _]} ->
{:ok, {:cuda, 0}}
_ ->
{:error, :device_not_available}
end
end
def select({:cuda, device_id}) when is_integer(device_id) do
info = Detector.detect()
case info.cuda do
%{devices: devices} when is_list(devices) ->
if Enum.any?(devices, &(&1.id == device_id)) do
{:ok, {:cuda, device_id}}
else
{:error, :device_not_available}
end
_ ->
{:error, :device_not_available}
end
end
def select(:mps) do
info = Detector.detect()
case info.mps do
%{available: true} ->
{:ok, :mps}
_ ->
{:error, :device_not_available}
end
end
def select(:rocm) do
info = Detector.detect()
case info.rocm do
%{devices: [_ | _]} ->
{:ok, {:rocm, 0}}
_ ->
{:error, :device_not_available}
end
end
def select({:rocm, device_id}) when is_integer(device_id) do
info = Detector.detect()
case info.rocm do
%{devices: devices} when is_list(devices) ->
if Enum.any?(devices, &(&1.id == device_id)) do
{:ok, {:rocm, device_id}}
else
{:error, :device_not_available}
end
_ ->
{:error, :device_not_available}
end
end
def select(_), do: {:error, :device_not_available}
@doc """
Selects the first available device from a preference list.
Tries each device in order until one is available, returning that device.
If no devices are available, returns `{:error, :no_device}`.
## Examples
iex> Hardware.Selector.select_with_fallback([:cuda, :mps, :cpu])
{:ok, :cpu} # if CUDA and MPS unavailable
"""
@spec select_with_fallback([device_preference()]) ::
{:ok, device()} | {:error, :no_device}
def select_with_fallback([]) do
{:error, :no_device}
end
def select_with_fallback([preference | rest]) do
case select(preference) do
{:ok, device} -> {:ok, device}
{:error, _} -> select_with_fallback(rest)
end
end
@doc """
Returns information about a selected device.
Returns a map with device details useful for logging and telemetry.
"""
@spec device_info(device()) :: map()
def device_info(:cpu) do
info = Detector.detect()
%{
type: :cpu,
name: info.cpu.model,
cores: info.cpu.cores,
threads: info.cpu.threads,
memory_mb: info.cpu.memory_total_mb
}
end
def device_info({:cuda, device_id}) do
info = Detector.detect()
case info.cuda do
%{devices: devices, version: version} ->
device = Enum.find(devices, &(&1.id == device_id))
if device do
%{
type: :cuda,
device_id: device_id,
name: device.name,
memory_total_mb: device.memory_total_mb,
memory_free_mb: device.memory_free_mb,
cuda_version: version,
compute_capability: device.compute_capability
}
else
%{type: :cuda, device_id: device_id, error: :device_not_found}
end
_ ->
%{type: :cuda, device_id: device_id, error: :cuda_not_available}
end
end
def device_info(:cuda) do
device_info({:cuda, 0})
end
def device_info(:mps) do
info = Detector.detect()
case info.mps do
%{available: true} = mps ->
%{
type: :mps,
name: mps.device_name,
memory_mb: mps.memory_total_mb
}
_ ->
%{type: :mps, error: :mps_not_available}
end
end
def device_info({:rocm, device_id}) do
info = Detector.detect()
case info.rocm do
%{devices: devices, version: version} ->
device = Enum.find(devices, &(&1.id == device_id))
if device do
%{
type: :rocm,
device_id: device_id,
name: device.name,
memory_total_mb: device.memory_total_mb,
rocm_version: version
}
else
%{type: :rocm, device_id: device_id, error: :device_not_found}
end
_ ->
%{type: :rocm, device_id: device_id, error: :rocm_not_available}
end
end
def device_info(:rocm) do
device_info({:rocm, 0})
end
end