Skip to content

How to enable Intel AMX in asm! on Linux? #107795

Closed
@jczaja

Description

@jczaja

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-target-featureArea: Enabling/disabling target features like AVX, Neon, etc.O-linuxOperating system: LinuxO-x86_64Target: x86-64 processors (like x86_64-*) (also known as amd64 and x64)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions