use std::fmt;
use std::path::PathBuf;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TritonBranch {
Stable,
Mlir,
Preview,
}
impl fmt::Display for TritonBranch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TritonBranch::Stable => write!(f, "release/internal/3.6.x"),
TritonBranch::Mlir => write!(f, "release/internal/3.6.x"),
TritonBranch::Preview => write!(f, "main_perf"),
}
}
}
#[derive(Debug, Clone)]
pub struct TritonConfig {
pub rocm_channel: String,
pub gpu_arch: String,
pub python_bin: String,
pub dry_run: bool,
}
impl Default for TritonConfig {
fn default() -> Self {
Self {
rocm_channel: "latest".to_string(),
gpu_arch: "gfx1100".to_string(),
python_bin: "python3".to_string(),
dry_run: false,
}
}
}
#[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>,
}
impl ShellCommand {
pub fn to_command_string(&self) -> String {
let env_prefix = self
.env
.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<_>>()
.join(" ");
let cmd = if self.args.is_empty() {
self.program.clone()
} else {
format!("{} {}", self.program, self.args.join(" "))
};
if env_prefix.is_empty() {
cmd
} else {
format!("{env_prefix} {cmd}")
}
}
}
pub struct TritonInstaller {
config: TritonConfig,
}
impl TritonInstaller {
pub fn new(config: TritonConfig) -> Self {
Self { config }
}
pub fn with_defaults() -> Self {
Self::new(TritonConfig::default())
}
pub fn select_branch(&self) -> TritonBranch {
if self.config.rocm_channel == "preview" || self.config.gpu_arch.starts_with("gfx12") {
TritonBranch::Preview
} else {
TritonBranch::Mlir
}
}
pub fn git_clone_url(&self) -> &'static str {
"https://github.com/ROCm/triton.git"
}
pub fn build_git_clone_command(&self, target_dir: &str) -> ShellCommand {
ShellCommand {
program: "git".to_string(),
args: vec![
"clone".to_string(),
self.git_clone_url().to_string(),
target_dir.to_string(),
],
env: vec![],
working_dir: None,
}
}
pub fn build_git_checkout_command(&self) -> ShellCommand {
let branch = self.select_branch();
ShellCommand {
program: "git".to_string(),
args: vec!["checkout".to_string(), branch.to_string()],
env: vec![],
working_dir: None,
}
}
pub fn build_prerequisites_command(&self) -> ShellCommand {
let use_break = self.supports_break_system_packages();
let mut args = vec!["-m".to_string(), "pip".to_string(), "install".to_string()];
if use_break {
args.push("--break-system-packages".to_string());
}
args.extend([
"--upgrade".to_string(),
"--no-cache-dir".to_string(),
"pip".to_string(),
"setuptools".to_string(),
"wheel".to_string(),
"packaging".to_string(),
"pybind11".to_string(),
"cmake".to_string(),
"ninja".to_string(),
]);
ShellCommand {
program: self.config.python_bin.clone(),
args,
env: vec![],
working_dir: None,
}
}
pub fn build_pip_install_command(&self, src_dir: &str) -> ShellCommand {
let use_break = self.supports_break_system_packages();
let mut args = vec!["-m".to_string(), "pip".to_string(), "install".to_string()];
if use_break {
args.push("--break-system-packages".to_string());
}
args.extend([
"--no-build-isolation".to_string(),
"--no-deps".to_string(),
".".to_string(),
]);
let nproc = std::thread::available_parallelism()
.map(|n| n.get().saturating_sub(1))
.unwrap_or(4);
let env = vec![
("GPU_ARCHS".to_string(), self.config.gpu_arch.clone()),
("TRITON_ROCM".to_string(), "1".to_string()),
("MAX_JOBS".to_string(), nproc.to_string()),
];
ShellCommand {
program: self.config.python_bin.clone(),
args,
env,
working_dir: Some(PathBuf::from(src_dir)),
}
}
fn supports_break_system_packages(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_git_clone_url() {
let installer = TritonInstaller::with_defaults();
assert_eq!(
installer.git_clone_url(),
"https://github.com/ROCm/triton.git"
);
}
#[test]
fn test_git_clone_command() {
let installer = TritonInstaller::with_defaults();
let cmd = installer.build_git_clone_command("/tmp/triton-rocm/triton");
assert_eq!(cmd.program, "git");
assert!(cmd.args.contains(&"clone".to_string()));
assert!(cmd.args.iter().any(|a| a.contains("ROCm/triton")));
}
#[test]
fn test_git_checkout_mlir() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "latest".to_string(),
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
let cmd = installer.build_git_checkout_command();
assert_eq!(cmd.program, "git");
assert!(cmd.args.contains(&"checkout".to_string()));
assert!(cmd.args.iter().any(|a| a == "release/internal/3.6.x"));
}
#[test]
fn test_git_checkout_preview() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "preview".to_string(),
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
let cmd = installer.build_git_checkout_command();
assert!(cmd.args.iter().any(|a| a == "main_perf"));
}
#[test]
fn test_git_checkout_gfx12() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "latest".to_string(),
gpu_arch: "gfx1200".to_string(),
..Default::default()
});
assert_eq!(installer.select_branch(), TritonBranch::Preview);
}
#[test]
fn test_prerequisites_command() {
let installer = TritonInstaller::with_defaults();
let cmd = installer.build_prerequisites_command();
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"pybind11".to_string()));
assert!(cmd.args.contains(&"cmake".to_string()));
assert!(cmd.args.contains(&"ninja".to_string()));
}
#[test]
fn test_pip_install_command() {
let installer = TritonInstaller::new(TritonConfig {
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
let cmd = installer.build_pip_install_command("/tmp/triton-rocm/triton/python");
assert_eq!(cmd.program, "python3");
assert!(cmd.args.contains(&"--no-build-isolation".to_string()));
assert!(cmd.args.contains(&"--no-deps".to_string()));
assert!(cmd.args.contains(&".".to_string()));
assert!(cmd
.env
.iter()
.any(|(k, v)| k == "GPU_ARCHS" && v == "gfx1100"));
assert!(cmd.env.iter().any(|(k, v)| k == "TRITON_ROCM" && v == "1"));
assert!(cmd.env.iter().any(|(k, _)| k == "MAX_JOBS"));
}
#[test]
fn test_branch_selection_latest() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "latest".to_string(),
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
assert_eq!(installer.select_branch(), TritonBranch::Mlir);
}
#[test]
fn test_branch_selection_stable() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "stable".to_string(),
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
assert_eq!(installer.select_branch(), TritonBranch::Mlir);
}
#[test]
fn test_branch_selection_preview() {
let installer = TritonInstaller::new(TritonConfig {
rocm_channel: "preview".to_string(),
gpu_arch: "gfx1100".to_string(),
..Default::default()
});
assert_eq!(installer.select_branch(), TritonBranch::Preview);
}
#[test]
fn test_command_string_format() {
let cmd = ShellCommand {
program: "git".to_string(),
args: vec![
"clone".to_string(),
"https://github.com/ROCm/triton.git".to_string(),
],
env: vec![],
working_dir: None,
};
assert_eq!(
cmd.to_command_string(),
"git clone https://github.com/ROCm/triton.git"
);
}
#[test]
fn test_command_string_with_env() {
let cmd = ShellCommand {
program: "pip".to_string(),
args: vec!["install".to_string()],
env: vec![
("TRITON_ROCM".to_string(), "1".to_string()),
("GPU_ARCHS".to_string(), "gfx1100".to_string()),
],
working_dir: None,
};
let s = cmd.to_command_string();
assert!(s.contains("TRITON_ROCM=1"));
assert!(s.contains("GPU_ARCHS=gfx1100"));
}
}