use crate::installers::common::RocmEnv;
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HipArchs {
Gfx1030,
Gfx1100,
Gfx1200,
Default,
}
impl HipArchs {
pub fn from_gpu_arch(gpu_arch: &str) -> Self {
if gpu_arch.starts_with("gfx103") {
HipArchs::Gfx1030
} else if gpu_arch.starts_with("gfx110") {
HipArchs::Gfx1100
} else if gpu_arch.starts_with("gfx120") {
HipArchs::Gfx1200
} else {
HipArchs::Default
}
}
pub fn cmake_hip_architectures(&self) -> &str {
match self {
HipArchs::Gfx1030 => "gfx1030",
HipArchs::Gfx1100 => "gfx1100;gfx1101;gfx1102;gfx1103",
HipArchs::Gfx1200 => "gfx1200;gfx1201",
HipArchs::Default => "gfx1100",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum OnnxInstallMethod {
#[default]
MigraphxWheel,
SourceBuild,
PrebuiltWheel,
}
pub const DEFAULT_ONNXRUNTIME_VERSION: &str = "1.27.1";
pub const PREBUILT_MIGRAPHX_VERSION: &str = "1.27.1";
pub const ONNX_INSTALL_METHOD_ENV: &str = "MLSTACK_ONNX_INSTALL_METHOD";
pub const ONNX_VERSION_ENV: &str = "MLSTACK_ONNX_VERSION";
pub fn install_method_from_env() -> OnnxInstallMethod {
match std::env::var(ONNX_INSTALL_METHOD_ENV)
.unwrap_or_default()
.trim()
.to_ascii_lowercase()
.as_str()
{
"source" | "source-build" | "src" => OnnxInstallMethod::SourceBuild,
"prebuilt" | "rocm" | "onnxruntime-rocm" => OnnxInstallMethod::PrebuiltWheel,
_ => OnnxInstallMethod::MigraphxWheel,
}
}
pub fn prebuilt_version_from_env() -> Option<String> {
std::env::var(ONNX_VERSION_ENV)
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
}
#[derive(Debug, Clone)]
pub struct OnnxRuntimeConfig {
pub python_bin: String,
pub dry_run: bool,
pub rocm_version: Option<String>,
pub rocm_release: Option<String>,
pub gpu_arch: Option<String>,
pub workdir: Option<PathBuf>,
pub eigen_path: Option<PathBuf>,
pub use_preinstalled_eigen: bool,
pub install_method: OnnxInstallMethod,
pub runtime_version: Option<String>,
pub prebuilt_version: Option<String>,
}
impl Default for OnnxRuntimeConfig {
fn default() -> Self {
Self {
python_bin: "python3".to_string(),
dry_run: false,
rocm_version: None,
rocm_release: None,
gpu_arch: None,
workdir: None,
eigen_path: None,
use_preinstalled_eigen: false,
install_method: OnnxInstallMethod::default(),
runtime_version: None,
prebuilt_version: None,
}
}
}
impl OnnxRuntimeConfig {
pub fn workdir(&self) -> PathBuf {
self.workdir
.clone()
.unwrap_or_else(|| std::env::temp_dir().join("onnxruntime-rocm"))
}
pub fn gpu_arch(&self) -> &str {
self.gpu_arch.as_deref().unwrap_or("gfx1100")
}
pub fn rocm_version(&self) -> &str {
self.rocm_version.as_deref().unwrap_or("7.2")
}
pub fn rocm_release(&self) -> &str {
self.rocm_release.as_deref().unwrap_or("7.2.4")
}
pub fn runtime_version(&self) -> &str {
match self.runtime_version.as_deref() {
Some(v) if !v.trim().is_empty() => v,
_ => DEFAULT_ONNXRUNTIME_VERSION,
}
}
pub fn prebuilt_version(&self) -> &str {
self.prebuilt_version
.as_deref()
.unwrap_or(PREBUILT_MIGRAPHX_VERSION)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ShellCommand {
pub program: String,
pub args: Vec<String>,
pub env: Vec<(String, String)>,
pub working_dir: Option<PathBuf>,
}
pub struct OnnxRuntimeInstaller {
config: OnnxRuntimeConfig,
}
impl OnnxRuntimeInstaller {
pub fn new(config: OnnxRuntimeConfig) -> Self {
Self { config }
}
pub fn with_defaults() -> Self {
Self::new(OnnxRuntimeConfig::default())
}
pub fn runtime_version(&self) -> &str {
self.config.runtime_version()
}
pub fn prebuilt_version(&self) -> &str {
self.config.prebuilt_version()
}
pub fn dependencies(&self) -> &[&str] {
&["rocm"]
}
pub fn build_prebuilt_install_command(&self) -> ShellCommand {
ShellCommand {
program: self.config.python_bin.clone(),
args: vec![
"-m".to_string(),
"pip".to_string(),
"install".to_string(),
"--upgrade".to_string(),
"--force-reinstall".to_string(),
"--no-deps".to_string(),
"--prefer-binary".to_string(),
"onnxruntime-rocm".to_string(),
],
env: vec![],
working_dir: None,
}
}
pub fn build_migraphx_install_command(&self) -> ShellCommand {
let spec = format!("onnxruntime-migraphx=={}", self.config.prebuilt_version());
ShellCommand {
program: self.config.python_bin.clone(),
args: vec![
"-m".to_string(),
"pip".to_string(),
"install".to_string(),
"--upgrade".to_string(),
"--force-reinstall".to_string(),
"--no-deps".to_string(),
"--no-cache-dir".to_string(),
spec,
],
env: vec![],
working_dir: None,
}
}
pub fn build_provider_validation_command(&self) -> ShellCommand {
let script = r#"
import ctypes
import os
import onnxruntime as ort
if not getattr(ort, "__version__", None) or not hasattr(ort, "get_available_providers"):
raise SystemExit(f"ONNX Runtime import incomplete: {getattr(ort, '__file__', '<unknown>')}")
priority = ["MIGraphXExecutionProvider", "ROCMExecutionProvider"]
available = ort.get_available_providers()
selected = next((p for p in priority if p in available), None)
if selected is None:
capi = os.path.join(os.path.dirname(ort.__file__), "capi")
loader_errors = []
for lib in ("libonnxruntime_providers_migraphx.so", "libonnxruntime_providers_rocm.so"):
path = os.path.join(capi, lib)
if os.path.exists(path):
try:
ctypes.CDLL(path)
except OSError as exc:
loader_errors.append(f"{lib}: {exc}")
raise SystemExit(
"ONNX Runtime AMD provider unavailable; expected MIGraphXExecutionProvider "
f"or legacy ROCMExecutionProvider; available={available}; "
f"loader_errors={loader_errors or 'none'}"
)
print(f"ONNX Runtime AMD provider ready: {selected}; available={available}")
"#;
ShellCommand {
program: self.config.python_bin.clone(),
args: vec!["-c".to_string(), script.trim().to_string()],
env: vec![],
working_dir: None,
}
}
pub fn build_model_optimizer_command(&self, model_path: &str) -> ShellCommand {
let optimized_path = format!("{}.optimized", model_path);
let script = format!(
"import onnxruntime as ort; \
providers = [p for p in ['MIGraphXExecutionProvider', 'ROCMExecutionProvider'] if p in ort.get_available_providers()]; \
assert providers, f'No AMD ONNX Runtime provider available: {{ort.get_available_providers()}}'; \
opts = ort.SessionOptions(); \
opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL; \
opts.optimized_model_filepath = '{optimized_path}'; \
ort.InferenceSession('{model_path}', opts, providers=providers); \
print('Optimized: {model_path} -> {optimized_path} using ' + providers[0])"
);
ShellCommand {
program: self.config.python_bin.clone(),
args: vec!["-c".to_string(), script],
env: vec![],
working_dir: None,
}
}
pub fn build_git_clone_command(&self) -> ShellCommand {
ShellCommand {
program: "git".to_string(),
args: vec![
"clone".to_string(),
"--recursive".to_string(),
"https://github.com/microsoft/onnxruntime.git".to_string(),
],
env: vec![],
working_dir: Some(self.config.workdir()),
}
}
pub fn build_git_checkout_command(&self) -> ShellCommand {
ShellCommand {
program: "git".to_string(),
args: vec![
"checkout".to_string(),
format!("v{}", self.config.runtime_version()),
],
env: vec![],
working_dir: Some(self.config.workdir().join("onnxruntime")),
}
}
pub fn build_git_submodule_command(&self) -> ShellCommand {
ShellCommand {
program: "git".to_string(),
args: vec![
"submodule".to_string(),
"update".to_string(),
"--init".to_string(),
"--recursive".to_string(),
],
env: vec![],
working_dir: Some(self.config.workdir().join("onnxruntime")),
}
}
pub fn build_build_command(&self, rocm_env: &RocmEnv) -> ShellCommand {
let rocm_path = rocm_env
.path()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| "/opt/rocm".to_string());
let hip_archs = HipArchs::from_gpu_arch(self.config.gpu_arch());
let nproc = std::thread::available_parallelism()
.map(|n| n.get().saturating_sub(1))
.unwrap_or(3);
let mut args = vec![
"--config".to_string(),
"Release".to_string(),
"--build_wheel".to_string(),
"--parallel".to_string(),
nproc.to_string(),
"--skip_tests".to_string(),
"--use_migraphx".to_string(),
"--migraphx_home".to_string(),
rocm_path.clone(),
];
if self.config.use_preinstalled_eigen {
if let Some(ref eigen_path) = self.config.eigen_path {
args.push("--use_preinstalled_eigen".to_string());
args.push("--eigen_path".to_string());
args.push(eigen_path.to_string_lossy().to_string());
}
}
let cmake_extra_defines = vec![
format!(
"CMAKE_HIP_ARCHITECTURES={}",
hip_archs.cmake_hip_architectures()
),
"CMAKE_CXX_STANDARD=20".to_string(),
"onnxruntime_USE_EXTERNAL_ABSEIL=OFF".to_string(),
"CMAKE_DISABLE_FIND_PACKAGE_re2=ON".to_string(),
"CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON".to_string(),
"CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON".to_string(),
"CMAKE_FIND_USE_PACKAGE_REGISTRY=OFF".to_string(),
"CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY=OFF".to_string(),
format!("CMAKE_PREFIX_PATH={}", rocm_path),
"re2_DIR=RE2_DIR-NOTFOUND".to_string(),
"CMAKE_POLICY_VERSION_MINIMUM=3.5".to_string(),
];
for define in cmake_extra_defines {
args.push("--cmake_extra_defines".to_string());
args.push(define);
}
if self.config.use_preinstalled_eigen {
if let Some(ref eigen_path) = self.config.eigen_path {
args.push("--cmake_extra_defines".to_string());
args.push(format!(
"FETCHCONTENT_SOURCE_DIR_EIGEN={}",
eigen_path.to_string_lossy()
));
args.push("--cmake_extra_defines".to_string());
args.push("FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER".to_string());
}
}
args.push("--allow_running_as_root".to_string());
let env = vec![];
ShellCommand {
program: "./build.sh".to_string(),
args,
env,
working_dir: Some(self.config.workdir().join("onnxruntime")),
}
}
pub fn build_uninstall_command(&self) -> ShellCommand {
ShellCommand {
program: self.config.python_bin.clone(),
args: vec![
"-m".to_string(),
"pip".to_string(),
"uninstall".to_string(),
"-y".to_string(),
"onnxruntime".to_string(),
"onnxruntime-rocm".to_string(),
"onnxruntime-gpu".to_string(),
"onnxruntime-migraphx".to_string(),
],
env: vec![],
working_dir: None,
}
}
pub fn build_wheel_install_command(&self) -> ShellCommand {
let wheel_path = self
.config
.workdir()
.join("onnxruntime")
.join("build/Linux/Release/dist/*.whl");
ShellCommand {
program: self.config.python_bin.clone(),
args: vec![
"-m".to_string(),
"pip".to_string(),
"install".to_string(),
wheel_path.to_string_lossy().to_string(),
],
env: vec![],
working_dir: None,
}
}
pub fn check_build_output(
&self,
stdout: &str,
stderr: &str,
exit_code: i32,
) -> Result<(), String> {
if exit_code != 0 {
let error_patterns = [
"CMake Error",
"error:",
"FAILED:",
"fatal error:",
"Build failed",
"ninja: build stopped",
"Could NOT find",
];
let combined = format!("{}\n{}", stdout, stderr);
let detected_errors: Vec<&str> = error_patterns
.iter()
.filter(|p| combined.contains(*p))
.copied()
.collect();
if detected_errors.is_empty() {
return Err(format!(
"ONNX Runtime build failed with exit code {} (no specific error pattern detected)",
exit_code
));
}
return Err(format!(
"ONNX Runtime build failed with exit code {}. Detected errors: {}",
exit_code,
detected_errors.join(", ")
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_build_command_uses_migraphx_recipe_not_use_rocm() {
let installer = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
rocm_version: Some("7.2.0".to_string()),
gpu_arch: Some("gfx1100".to_string()),
..Default::default()
});
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert_eq!(cmd.program, "./build.sh");
assert!(cmd.args.contains(&"--use_migraphx".to_string()));
assert!(cmd.args.contains(&"--migraphx_home".to_string()));
assert!(cmd.args.contains(&"--build_wheel".to_string()));
assert!(cmd.args.contains(&"--skip_tests".to_string()));
assert!(cmd.args.contains(&"--allow_running_as_root".to_string()));
assert!(cmd.args.iter().any(|a| a == "/opt/rocm"));
for removed in ["--use_rocm", "--rocm_home", "--rocm_version"] {
assert!(
!cmd.args.contains(&removed.to_string()),
"removed flag {removed} must not appear: {:?}",
cmd.args
);
}
}
#[test]
fn test_build_command_has_hip_architectures() {
let installer = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
gpu_arch: Some("gfx1100".to_string()),
..Default::default()
});
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(cmd
.args
.iter()
.any(|a| a.contains("CMAKE_HIP_ARCHITECTURES=gfx1100;gfx1101;gfx1102;gfx1103")));
}
#[test]
fn test_build_command_has_cmake_extra_defines() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(cmd
.args
.iter()
.any(|a| a.contains("onnxruntime_USE_EXTERNAL_ABSEIL=OFF")));
assert!(cmd
.args
.iter()
.any(|a| a.contains("CMAKE_DISABLE_FIND_PACKAGE_re2=ON")));
assert!(cmd
.args
.iter()
.any(|a| a.contains("CMAKE_POLICY_VERSION_MINIMUM=3.5")));
}
#[test]
fn test_build_command_includes_cmake_cxx_standard_20() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(
cmd.args.iter().any(|a| a.contains("CMAKE_CXX_STANDARD=20")),
"build command must include CMAKE_CXX_STANDARD=20 cmake extra define, got args: {:?}",
cmd.args
);
}
#[test]
fn test_build_command_cmake_cxx_standard_is_cmake_extra_define() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
let define_idx = cmd
.args
.iter()
.position(|a| a.contains("CMAKE_CXX_STANDARD=20"));
assert!(
define_idx.is_some(),
"CMAKE_CXX_STANDARD=20 not found in args"
);
let idx = define_idx.unwrap();
assert!(
idx > 0 && cmd.args[idx - 1] == "--cmake_extra_defines",
"CMAKE_CXX_STANDARD=20 must be preceded by --cmake_extra_defines"
);
}
#[test]
fn test_build_command_does_not_override_env_vars() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(
cmd.env.is_empty(),
"ONNX build must inherit ~/.mlstack_env, got env: {:?}",
cmd.env
);
}
#[test]
fn test_build_command_has_parallel_flag() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(cmd.args.contains(&"--parallel".to_string()));
}
#[test]
fn test_build_command_env_vars() {
let installer = OnnxRuntimeInstaller::with_defaults();
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(cmd.env.is_empty());
}
#[test]
fn test_build_command_with_eigen() {
let installer = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
use_preinstalled_eigen: true,
eigen_path: Some(PathBuf::from("/usr/include/eigen3")),
..Default::default()
});
let rocm_env = RocmEnv::from_known(Some(PathBuf::from("/opt/rocm")), "7.2.0".to_string());
let cmd = installer.build_build_command(&rocm_env);
assert!(cmd.args.contains(&"--use_preinstalled_eigen".to_string()));
assert!(cmd.args.iter().any(|a| a.contains("/usr/include/eigen3")));
assert!(cmd
.args
.iter()
.any(|a| a.contains("FETCHCONTENT_SOURCE_DIR_EIGEN")));
}
#[test]
fn test_wheel_install_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_wheel_install_command();
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"-m".to_string()));
assert!(cmd.args.contains(&"pip".to_string()));
assert!(cmd.args.contains(&"install".to_string()));
assert!(cmd
.args
.iter()
.any(|a| a.contains("build/Linux/Release/dist/*.whl")));
}
#[test]
fn test_uninstall_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_uninstall_command();
assert!(cmd.args.contains(&"uninstall".to_string()));
assert!(cmd.args.contains(&"-y".to_string()));
assert!(cmd.args.contains(&"onnxruntime".to_string()));
assert!(cmd.args.contains(&"onnxruntime-rocm".to_string()));
assert!(cmd.args.contains(&"onnxruntime-gpu".to_string()));
assert!(cmd.args.contains(&"onnxruntime-migraphx".to_string()));
}
#[test]
fn test_prebuilt_install_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_prebuilt_install_command();
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"-m".to_string()));
assert!(cmd.args.contains(&"pip".to_string()));
assert!(cmd.args.contains(&"--upgrade".to_string()));
assert!(cmd.args.contains(&"--force-reinstall".to_string()));
assert!(cmd.args.contains(&"--no-deps".to_string()));
assert!(cmd.args.contains(&"--prefer-binary".to_string()));
assert!(cmd.args.contains(&"onnxruntime-rocm".to_string()));
assert!(cmd.env.is_empty());
}
#[test]
fn test_git_clone_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_git_clone_command();
assert_eq!(cmd.program, "git");
assert!(cmd.args.contains(&"clone".to_string()));
assert!(cmd.args.contains(&"--recursive".to_string()));
assert!(cmd.args.iter().any(|a| a.contains("microsoft/onnxruntime")));
}
#[test]
fn test_git_checkout_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_git_checkout_command();
assert!(cmd
.args
.contains(&format!("v{}", DEFAULT_ONNXRUNTIME_VERSION)));
assert!(cmd.args.contains(&"v1.27.1".to_string()));
}
#[test]
fn test_git_checkout_command_follows_runtime_version() {
let installer = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
runtime_version: Some("1.25.0".to_string()),
..Default::default()
});
let cmd = installer.build_git_checkout_command();
assert!(cmd.args.contains(&"v1.25.0".to_string()));
}
#[test]
fn test_runtime_version_filters_empty_to_default() {
let empty = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
runtime_version: Some(String::new()),
..Default::default()
});
assert_eq!(empty.config.runtime_version(), DEFAULT_ONNXRUNTIME_VERSION);
assert_ne!(empty.config.runtime_version(), "");
let ws = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
runtime_version: Some(" ".to_string()),
..Default::default()
});
assert_eq!(ws.config.runtime_version(), DEFAULT_ONNXRUNTIME_VERSION);
let real = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
runtime_version: Some("1.25.0".to_string()),
..Default::default()
});
assert_eq!(real.config.runtime_version(), "1.25.0");
}
#[test]
fn test_hip_archs_gfx1030() {
let archs = HipArchs::from_gpu_arch("gfx1030");
assert_eq!(archs.cmake_hip_architectures(), "gfx1030");
}
#[test]
fn test_hip_archs_gfx1100() {
let archs = HipArchs::from_gpu_arch("gfx1100");
assert_eq!(
archs.cmake_hip_architectures(),
"gfx1100;gfx1101;gfx1102;gfx1103"
);
}
#[test]
fn test_hip_archs_gfx1200() {
let archs = HipArchs::from_gpu_arch("gfx1200");
assert_eq!(archs.cmake_hip_architectures(), "gfx1200;gfx1201");
}
#[test]
fn test_hip_archs_default() {
let archs = HipArchs::from_gpu_arch("gfx900");
assert_eq!(archs.cmake_hip_architectures(), "gfx1100");
}
#[test]
fn test_dependencies() {
let installer = OnnxRuntimeInstaller::with_defaults();
let deps = installer.dependencies();
assert!(deps.contains(&"rocm"));
}
#[test]
fn test_build_error_cmake() {
let installer = OnnxRuntimeInstaller::with_defaults();
let result = installer.check_build_output("", "CMake Error at cmake/CMakeLists.txt:42", 1);
assert!(result.is_err());
assert!(result.unwrap_err().contains("CMake Error"));
}
#[test]
fn test_build_error_ninja() {
let installer = OnnxRuntimeInstaller::with_defaults();
let result =
installer.check_build_output("ninja: build stopped: subcommand failed.", "", 1);
assert!(result.is_err());
assert!(result.unwrap_err().contains("ninja: build stopped"));
}
#[test]
fn test_build_error_success() {
let installer = OnnxRuntimeInstaller::with_defaults();
let result = installer.check_build_output("Build succeeded", "", 0);
assert!(result.is_ok());
}
#[test]
fn test_config_defaults() {
let config = OnnxRuntimeConfig::default();
assert_eq!(config.python_bin, "python3");
assert!(!config.dry_run);
assert!(config.rocm_version.is_none());
assert!(config.rocm_release.is_none());
assert!(config.gpu_arch.is_none());
assert!(config.workdir.is_none());
assert!(!config.use_preinstalled_eigen);
assert!(config.eigen_path.is_none());
assert_eq!(config.install_method, OnnxInstallMethod::MigraphxWheel);
assert_eq!(config.runtime_version(), DEFAULT_ONNXRUNTIME_VERSION);
assert_eq!(config.prebuilt_version(), PREBUILT_MIGRAPHX_VERSION);
}
#[test]
fn test_prebuilt_version_defaults_to_pinned() {
let installer = OnnxRuntimeInstaller::with_defaults();
assert_eq!(installer.prebuilt_version(), PREBUILT_MIGRAPHX_VERSION);
assert_eq!(installer.prebuilt_version(), DEFAULT_ONNXRUNTIME_VERSION);
assert_eq!(installer.prebuilt_version(), "1.27.1");
}
#[test]
fn test_install_method_from_env() {
let _env = crate::test_support::lock_env();
std::env::remove_var(ONNX_INSTALL_METHOD_ENV);
assert_eq!(install_method_from_env(), OnnxInstallMethod::MigraphxWheel);
for (v, expected) in [
("source", OnnxInstallMethod::SourceBuild),
("SOURCE-BUILD", OnnxInstallMethod::SourceBuild),
("prebuilt", OnnxInstallMethod::PrebuiltWheel),
("rocm", OnnxInstallMethod::PrebuiltWheel),
("migraphx", OnnxInstallMethod::MigraphxWheel),
("", OnnxInstallMethod::MigraphxWheel),
] {
if v.is_empty() {
std::env::remove_var(ONNX_INSTALL_METHOD_ENV);
} else {
std::env::set_var(ONNX_INSTALL_METHOD_ENV, v);
}
assert_eq!(install_method_from_env(), expected, "for {v:?}");
}
}
#[test]
fn test_prebuilt_version_from_env_override() {
let _env = crate::test_support::lock_env();
std::env::remove_var(ONNX_VERSION_ENV);
assert_eq!(prebuilt_version_from_env(), None);
std::env::set_var(ONNX_VERSION_ENV, " 1.30.0 ");
assert_eq!(prebuilt_version_from_env(), Some("1.30.0".to_string()));
std::env::set_var(ONNX_VERSION_ENV, " ");
assert_eq!(prebuilt_version_from_env(), None);
}
#[test]
fn test_prebuilt_version_overridable() {
let installer = OnnxRuntimeInstaller::new(OnnxRuntimeConfig {
prebuilt_version: Some("1.23.2".to_string()),
..Default::default()
});
assert_eq!(installer.prebuilt_version(), "1.23.2");
}
#[test]
fn test_migraphx_install_command_pypi() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_migraphx_install_command();
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"-m".to_string()));
assert!(cmd.args.contains(&"pip".to_string()));
assert!(cmd.args.contains(&"install".to_string()));
assert!(cmd.args.contains(&"--upgrade".to_string()));
assert!(cmd.args.contains(&"--force-reinstall".to_string()));
assert!(cmd.args.contains(&"--no-deps".to_string()));
assert!(cmd.args.contains(&"--no-cache-dir".to_string()));
assert!(cmd
.args
.iter()
.any(|a| a == &format!("onnxruntime-migraphx=={}", PREBUILT_MIGRAPHX_VERSION)));
assert!(
!cmd.args.iter().any(|a| a.contains("repo.radeon.com")),
"must not use the AMD manylinux repo (it lags and 404s): {:?}",
cmd.args
);
assert!(cmd.env.is_empty());
}
#[test]
fn test_provider_validation_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_provider_validation_command();
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"-c".to_string()));
let script = &cmd.args[1];
assert!(script.contains("MIGraphXExecutionProvider"));
assert!(script.contains("ROCMExecutionProvider"));
assert!(script.contains("ctypes.CDLL"));
assert!(script.contains("loader_errors"));
assert!(cmd.env.is_empty());
}
#[test]
fn test_model_optimizer_command() {
let installer = OnnxRuntimeInstaller::with_defaults();
let cmd = installer.build_model_optimizer_command("/path/to/model.onnx");
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"-c".to_string()));
let script = &cmd.args[1];
assert!(script.contains("MIGraphXExecutionProvider"));
assert!(script.contains("ROCMExecutionProvider"));
assert!(!script.contains("CPUExecutionProvider"));
assert!(script.contains("ORT_ENABLE_ALL"));
assert!(script.contains("/path/to/model.onnx"));
assert!(script.contains("/path/to/model.onnx.optimized"));
assert!(cmd.env.is_empty());
}
#[test]
fn test_install_method_default() {
assert_eq!(
OnnxInstallMethod::default(),
OnnxInstallMethod::MigraphxWheel
);
}
}