Description
Hi,
I want to use in Rust (via inline assembly) Intel AMX instruction set.
AMX support is by default disabled in Linux Kernel due to significant amount of memory(~10KB) that has to be save on stack when there is context switching for programs using AMX. To enable AMX we need processor
with this capability (sapphirerapids), recent enough Linux kernel (5.16+) and stacks of FPU&sigalt to be of a size enough to be able to store AMX tiles (registers). Article on enabling AMX is here.
I have implemented a programs to enable and test AMX: one in C++ and the other in Rust. The one in C++ does initialize AMX properly, but the Rust program is not able to initialize AMX properly (likely due to stack sizes being not big enough, see "PROGRAM EXITS HERE in Rust example"). Similar problem was described for python programming language. Please advice how to have AMX support enabled in Rust on SapphireRapids under Linux.
Details:
C++ program:
#include <iostream>
namespace {
#include <unistd.h>
#include <sys/syscall.h>
#define XFEATURE_XTILECFG 17
#define XFEATURE_XTILEDATA 18
#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG)
#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA)
#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA)
#define ARCH_GET_XCOMP_PERM 0x1022
#define ARCH_REQ_XCOMP_PERM 0x1023
bool init() {
unsigned long bitmask = 0;
long status = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
if (0 != status) return false;
if (bitmask & XFEATURE_MASK_XTILEDATA) return true;
status = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
if (0 != status)
return false; // XFEATURE_XTILEDATA setup is failed, TMUL usage is not allowed
status = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask);
// XFEATURE_XTILEDATA setup is failed, can't use TMUL
if (0 != status || !(bitmask & XFEATURE_MASK_XTILEDATA)) return false;
// XFEATURE_XTILEDATA set successfully, TMUL usage is allowed
return true;
}
}
int main(int argc, char **argv) {
puts("Using system call to enable AMX...");
if (!init()) {
printf("Error: AMX is not available\n");
return 1;
}
puts("...AMX is now enabled!\n");
}
Rust:
main:rs:
use syscalls::*;
fn initialize_amx_if_available() -> bool {
const ARCH_GET_XCOMP_PERM: usize = 0x1022;
const ARCH_REQ_XCOMP_PERM: usize = 0x1023;
const XFEATURE_XTILECFG: usize = 17;
const XFEATURE_XTILEDATA: usize = 18;
const XFEATURE_MASK_XTILEDATA: usize = 1 << XFEATURE_XTILEDATA;
const XFEATURE_MASK_XTILECFG: usize = 1 << XFEATURE_XTILECFG;
const XFEATURE_MASK_XTILE: usize = XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA;
let bitmask: [usize; 1] = [0; 1];
let mut status: usize = 0;
unsafe {
let maybe_status = syscall!(Sysno::arch_prctl, ARCH_GET_XCOMP_PERM, bitmask.as_ptr());
match maybe_status {
Ok(s) => status = s,
Err(_) => {
println!("AMX not supported!");
return false;
}
}
}
if (bitmask[0] & XFEATURE_MASK_XTILEDATA) != 0 {
return true;
}
unsafe {
let maybe_status = syscall!(Sysno::arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA);
match maybe_status {
Ok(s) => status = s,
Err(err) => {
println!("AMX Error: XFEATURE_XTILEDATA setup is failed, TMUL usage is not allowed! Error: {}",err);
return false; //<========================================== PROGRAM EXITS HERE!!!
}
}
}
unsafe {
status = syscall!(Sysno::arch_prctl, ARCH_GET_XCOMP_PERM, bitmask.as_ptr())
.expect("Error: ARCH_PRCTL syscall failed!");
}
if status != 0 || ((bitmask[0] & XFEATURE_MASK_XTILEDATA) == 0) {
println!("AMX not supported!");
return false;
}
// XFEATURE_XTILEDATA set successfully, TMUL usage is allowed
true
}
fn main() {
if initialize_amx_if_available() == true {
println!("Success: AMX Enabled!");
} else {
println!("ERROR: Could not enable AMX!");
}
}
Cargo.toml
[package]
name = "test-enable-amx"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syscalls = "0.6.7"
building:RUSTFLAGS='-C target-cpu=sapphirerapids -C target-feature=+amx-int8,+amx-bf16,+amx-tile' cargo build
toolchains used: 1.67.0 , 1.69.0-nightly
Linux kernel: 5.19.0-1.el8.elrepo.x86_64
OS: Centos 8.5