mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Merge 5bb8b45e33
into f609e1ddaf
This commit is contained in:
commit
a751592a12
5 changed files with 109 additions and 12 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -5916,6 +5916,7 @@ dependencies = [
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-platform-tags",
|
"uv-platform-tags",
|
||||||
"uv-static",
|
"uv-static",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -24,6 +24,7 @@ serde = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
walkdir = { workspace = true }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use uv_pep440::Version;
|
use uv_pep440::Version;
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
|
@ -13,6 +15,10 @@ pub enum AcceleratorError {
|
||||||
Version(#[from] uv_pep440::VersionParseError),
|
Version(#[from] uv_pep440::VersionParseError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Utf8(#[from] std::string::FromUtf8Error),
|
Utf8(#[from] std::string::FromUtf8Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
ParseInt(#[from] std::num::ParseIntError),
|
||||||
|
#[error(transparent)]
|
||||||
|
WalkDir(#[from] walkdir::Error),
|
||||||
#[error("Unknown AMD GPU architecture: {0}")]
|
#[error("Unknown AMD GPU architecture: {0}")]
|
||||||
UnknownAmdGpuArchitecture(String),
|
UnknownAmdGpuArchitecture(String),
|
||||||
}
|
}
|
||||||
|
@ -30,6 +36,10 @@ pub enum Accelerator {
|
||||||
Amd {
|
Amd {
|
||||||
gpu_architecture: AmdGpuArchitecture,
|
gpu_architecture: AmdGpuArchitecture,
|
||||||
},
|
},
|
||||||
|
/// The Intel GPU (XPU).
|
||||||
|
///
|
||||||
|
/// Currently, Intel GPUs do not depend on a driver/toolkit version at this level.
|
||||||
|
Xpu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Accelerator {
|
impl std::fmt::Display for Accelerator {
|
||||||
|
@ -37,21 +47,28 @@ impl std::fmt::Display for Accelerator {
|
||||||
match self {
|
match self {
|
||||||
Self::Cuda { driver_version } => write!(f, "CUDA {driver_version}"),
|
Self::Cuda { driver_version } => write!(f, "CUDA {driver_version}"),
|
||||||
Self::Amd { gpu_architecture } => write!(f, "AMD {gpu_architecture}"),
|
Self::Amd { gpu_architecture } => write!(f, "AMD {gpu_architecture}"),
|
||||||
|
Self::Xpu => write!(f, "Intel GPU (XPU) detected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Accelerator {
|
impl Accelerator {
|
||||||
/// Detect the CUDA driver version from the system.
|
/// Detect the GPU driver/architecture version from the system.
|
||||||
///
|
///
|
||||||
/// Query, in order:
|
/// Query, in order:
|
||||||
/// 1. The `UV_CUDA_DRIVER_VERSION` environment variable.
|
/// 1. The `UV_CUDA_DRIVER_VERSION` environment variable.
|
||||||
/// 2. The `UV_AMD_GPU_ARCHITECTURE` environment variable.
|
/// 2. The `UV_AMD_GPU_ARCHITECTURE` environment variable.
|
||||||
/// 2. `/sys/module/nvidia/version`, which contains the driver version (e.g., `550.144.03`).
|
/// 3. `/sys/module/nvidia/version`, which contains the driver version (e.g., `550.144.03`).
|
||||||
/// 3. `/proc/driver/nvidia/version`, which contains the driver version among other information.
|
/// 4. `/proc/driver/nvidia/version`, which contains the driver version among other information.
|
||||||
/// 4. `nvidia-smi --query-gpu=driver_version --format=csv,noheader`.
|
/// 5. `nvidia-smi --query-gpu=driver_version --format=csv,noheader`.
|
||||||
/// 5. `rocm_agent_enumerator`, which lists the AMD GPU architectures.
|
/// 6. `rocm_agent_enumerator`, which lists the AMD GPU architectures.
|
||||||
|
/// 7. `/sys/bus/pci/devices`, filtering for the Intel GPU via PCI.
|
||||||
pub fn detect() -> Result<Option<Self>, AcceleratorError> {
|
pub fn detect() -> Result<Option<Self>, AcceleratorError> {
|
||||||
|
// Constants used for PCI device detection
|
||||||
|
const PCI_BASE_CLASS_MASK: u32 = 0x00ff_0000;
|
||||||
|
const PCI_BASE_CLASS_DISPLAY: u32 = 0x0003_0000;
|
||||||
|
const PCI_VENDOR_ID_INTEL: u32 = 0x8086;
|
||||||
|
|
||||||
// Read from `UV_CUDA_DRIVER_VERSION`.
|
// Read from `UV_CUDA_DRIVER_VERSION`.
|
||||||
if let Ok(driver_version) = std::env::var(EnvVars::UV_CUDA_DRIVER_VERSION) {
|
if let Ok(driver_version) = std::env::var(EnvVars::UV_CUDA_DRIVER_VERSION) {
|
||||||
let driver_version = Version::from_str(&driver_version)?;
|
let driver_version = Version::from_str(&driver_version)?;
|
||||||
|
@ -150,6 +167,39 @@ impl Accelerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read from `/sys/bus/pci/devices` to filter for Intel GPU via PCI.
|
||||||
|
match WalkDir::new("/sys/bus/pci/devices")
|
||||||
|
.min_depth(1)
|
||||||
|
.max_depth(1)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
{
|
||||||
|
Ok(entries) => {
|
||||||
|
for entry in entries {
|
||||||
|
match parse_pci_device_ids(entry.path()) {
|
||||||
|
Ok((class, vendor)) => {
|
||||||
|
if (class & PCI_BASE_CLASS_MASK) == PCI_BASE_CLASS_DISPLAY
|
||||||
|
&& vendor == PCI_VENDOR_ID_INTEL
|
||||||
|
{
|
||||||
|
debug!("Detected Intel GPU from PCI: vendor=0x{:04x}", vendor);
|
||||||
|
return Ok(Some(Self::Xpu));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Failed to parse PCI device IDs: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e)
|
||||||
|
if e.io_error()
|
||||||
|
.is_some_and(|io| io.kind() == std::io::ErrorKind::NotFound) => {}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Failed to read PCI device directory with WalkDir: {e}");
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug!("Failed to detect GPU driver version");
|
debug!("Failed to detect GPU driver version");
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -180,6 +230,22 @@ fn parse_proc_driver_nvidia_version(content: &str) -> Result<Option<Version>, Ac
|
||||||
Ok(Some(driver_version))
|
Ok(Some(driver_version))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads and parses the PCI class and vendor ID from a given device path under `/sys/bus/pci/devices`.
|
||||||
|
fn parse_pci_device_ids(device_path: &Path) -> Result<(u32, u32), AcceleratorError> {
|
||||||
|
// Parse, e.g.:
|
||||||
|
// ```text
|
||||||
|
// - `class`: a hexadecimal string such as `0x030000`
|
||||||
|
// - `vendor`: a hexadecimal string such as `0x8086`
|
||||||
|
// ```
|
||||||
|
let class_content = fs_err::read_to_string(device_path.join("class"))?;
|
||||||
|
let pci_class = u32::from_str_radix(class_content.trim().trim_start_matches("0x"), 16)?;
|
||||||
|
|
||||||
|
let vendor_content = fs_err::read_to_string(device_path.join("vendor"))?;
|
||||||
|
let pci_vendor = u32::from_str_radix(vendor_content.trim().trim_start_matches("0x"), 16)?;
|
||||||
|
|
||||||
|
Ok((pci_class, pci_vendor))
|
||||||
|
}
|
||||||
|
|
||||||
/// A GPU architecture for AMD GPUs.
|
/// A GPU architecture for AMD GPUs.
|
||||||
///
|
///
|
||||||
/// See: <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html>
|
/// See: <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html>
|
||||||
|
|
|
@ -185,6 +185,8 @@ pub enum TorchStrategy {
|
||||||
os: Os,
|
os: Os,
|
||||||
gpu_architecture: AmdGpuArchitecture,
|
gpu_architecture: AmdGpuArchitecture,
|
||||||
},
|
},
|
||||||
|
/// Select the appropriate PyTorch index based on the operating system and Intel GPU presence.
|
||||||
|
Xpu { os: Os },
|
||||||
/// Use the specified PyTorch index.
|
/// Use the specified PyTorch index.
|
||||||
Backend(TorchBackend),
|
Backend(TorchBackend),
|
||||||
}
|
}
|
||||||
|
@ -202,6 +204,7 @@ impl TorchStrategy {
|
||||||
os: os.clone(),
|
os: os.clone(),
|
||||||
gpu_architecture,
|
gpu_architecture,
|
||||||
}),
|
}),
|
||||||
|
Some(Accelerator::Xpu) => Ok(Self::Xpu { os: os.clone() }),
|
||||||
None => Ok(Self::Backend(TorchBackend::Cpu)),
|
None => Ok(Self::Backend(TorchBackend::Cpu)),
|
||||||
},
|
},
|
||||||
TorchMode::Cpu => Ok(Self::Backend(TorchBackend::Cpu)),
|
TorchMode::Cpu => Ok(Self::Backend(TorchBackend::Cpu)),
|
||||||
|
@ -347,9 +350,27 @@ impl TorchStrategy {
|
||||||
Either::Right(Either::Left(std::iter::once(TorchBackend::Cpu.index_url())))
|
Either::Right(Either::Left(std::iter::once(TorchBackend::Cpu.index_url())))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TorchStrategy::Backend(backend) => {
|
TorchStrategy::Xpu { os } => match os {
|
||||||
Either::Right(Either::Right(std::iter::once(backend.index_url())))
|
Os::Manylinux { .. } => Either::Right(Either::Right(Either::Left(
|
||||||
}
|
std::iter::once(TorchBackend::Xpu.index_url()),
|
||||||
|
))),
|
||||||
|
Os::Windows
|
||||||
|
| Os::Musllinux { .. }
|
||||||
|
| Os::Macos { .. }
|
||||||
|
| Os::FreeBsd { .. }
|
||||||
|
| Os::NetBsd { .. }
|
||||||
|
| Os::OpenBsd { .. }
|
||||||
|
| Os::Dragonfly { .. }
|
||||||
|
| Os::Illumos { .. }
|
||||||
|
| Os::Haiku { .. }
|
||||||
|
| Os::Android { .. }
|
||||||
|
| Os::Pyodide { .. } => {
|
||||||
|
Either::Right(Either::Left(std::iter::once(TorchBackend::Cpu.index_url())))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TorchStrategy::Backend(backend) => Either::Right(Either::Right(Either::Right(
|
||||||
|
std::iter::once(backend.index_url()),
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,10 +444,10 @@ $ # With an environment variable.
|
||||||
$ UV_TORCH_BACKEND=auto uv pip install torch
|
$ UV_TORCH_BACKEND=auto uv pip install torch
|
||||||
```
|
```
|
||||||
|
|
||||||
When enabled, uv will query for the installed CUDA driver and AMD GPU versions then use the
|
When enabled, uv will query for the installed CUDA driver, AMD GPU versions and Intel GPU presence
|
||||||
most-compatible PyTorch index for all relevant packages (e.g., `torch`, `torchvision`, etc.). If no
|
then use the most-compatible PyTorch index for all relevant packages (e.g., `torch`, `torchvision`,
|
||||||
such GPU is found, uv will fall back to the CPU-only index. uv will continue to respect existing
|
etc.). If no such GPU is found, uv will fall back to the CPU-only index. uv will continue to respect
|
||||||
index configuration for any packages outside the PyTorch ecosystem.
|
existing index configuration for any packages outside the PyTorch ecosystem.
|
||||||
|
|
||||||
You can also select a specific backend (e.g., CUDA 12.6) with `--torch-backend=cu126` (or
|
You can also select a specific backend (e.g., CUDA 12.6) with `--torch-backend=cu126` (or
|
||||||
`UV_TORCH_BACKEND=cu126`):
|
`UV_TORCH_BACKEND=cu126`):
|
||||||
|
@ -460,4 +460,12 @@ $ # With an environment variable.
|
||||||
$ UV_TORCH_BACKEND=cu126 uv pip install torch torchvision
|
$ UV_TORCH_BACKEND=cu126 uv pip install torch torchvision
|
||||||
```
|
```
|
||||||
|
|
||||||
|
On Windows, Intel GPU (XPU) is not automatically selected with `--torch-backend=auto`, but you can
|
||||||
|
manually specify it using `--torch-backend=xpu`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ # Manual selection for Intel GPU.
|
||||||
|
$ uv pip install torch torchvision --torch-backend=xpu
|
||||||
|
```
|
||||||
|
|
||||||
At present, `--torch-backend` is only available in the `uv pip` interface.
|
At present, `--torch-backend` is only available in the `uv pip` interface.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue