cpu, doc, tests: add AMX ISA utilities
Co-authored-by: Nikita Shustrov <nikita.a.shustrov@intel.com>
This commit is contained in:
co-authored by
Nikita Shustrov
parent
8192cab514
commit
1ec78a431d
+5
-1
@@ -34,10 +34,14 @@ The library is optimized for the following CPUs:
|
||||
* Intel(R) Xeon Phi(TM) processor (formerly Knights Landing and Knights Mill)
|
||||
* Intel Xeon Scalable processor (formerly Skylake, Cascade Lake, and Cooper
|
||||
Lake)
|
||||
* future Intel Xeon Scalable processor (code name Sapphire Rapids)
|
||||
|
||||
oneDNN detects the instruction set architecture (ISA) at runtime and uses
|
||||
just-in-time (JIT) code generation to deploy the code optimized
|
||||
for the latest supported ISA.
|
||||
for the latest supported ISA. Future ISAs may have initial support in the
|
||||
library disabled by default and require the use of run-time controls to enable
|
||||
them. See CPU dispatcher control (https://oneapi-src.github.io/oneDNN/dev_guide_cpu_dispatcher_control.html)
|
||||
for more details.
|
||||
|
||||
The library is optimized for the following GPUs:
|
||||
* Intel HD Graphics
|
||||
|
||||
@@ -104,10 +104,15 @@ The library is optimized for the following CPUs:
|
||||
* Intel(R) Xeon Phi(TM) processor (formerly Knights Landing and Knights Mill)
|
||||
* Intel Xeon Scalable processor (formerly Skylake, Cascade Lake, and Cooper
|
||||
Lake)
|
||||
* future Intel Xeon Scalable processor (code name Sapphire Rapids)
|
||||
|
||||
On a CPU based on Intel 64 or on AMD64 architecture, oneDNN detects
|
||||
the instruction set architecture (ISA) at runtime and uses just-in-time (JIT)
|
||||
code generation to deploy the code optimized for the latest supported ISA.
|
||||
Future ISAs may have initial support in the library disabled by default and
|
||||
require the use of run-time controls to enable them. See
|
||||
[CPU dispatcher control](https://oneapi-src.github.io/oneDNN/dev_guide_cpu_dispatcher_control.html)
|
||||
for more details.
|
||||
|
||||
> **WARNING**
|
||||
>
|
||||
|
||||
@@ -19,7 +19,9 @@ At build-time, support for this feature is controlled via cmake option
|
||||
|
||||
When the feature is enabled at build-time, the `DNNL_MAX_CPU_ISA` environment
|
||||
variable can be used to limit processor features oneDNN is able to detect to
|
||||
certain Instruction Set Architecture (ISA) and older instruction sets.
|
||||
certain Instruction Set Architecture (ISA) and older instruction sets. It can
|
||||
also be used to enable ISAs with initial support in the library that are
|
||||
otherwise disabled by default.
|
||||
|
||||
| Environment variable | Value | Description
|
||||
| :--- | :--- | :---
|
||||
@@ -31,12 +33,13 @@ certain Instruction Set Architecture (ISA) and older instruction sets.
|
||||
| | AVX512_CORE | Intel AVX-512 with AVX512BW, AVX512VL, and AVX512DQ extensions
|
||||
| | AVX512_CORE_VNNI | Intel AVX-512 with Intel Deep Learning Boost (Intel DL Boost)
|
||||
| | AVX512_CORE_BF16 | Intel AVX-512 with Intel DL Boost and bfloat16 support
|
||||
| | **ALL** | **No restrictions on ISA (default)**
|
||||
| | **ALL** | **No restrictions on the above ISAs, but excludes the below ISAs with initial support in the library (default)**
|
||||
| | AVX512_CORE_AMX | Intel AVX-512 with Intel DL Boost and bfloat16 support and Intel Advanced Matrix Extensions (Intel AMX) with 8-bit integer and bfloat16 support (**initial support**)
|
||||
|
||||
@note The ISAs are partially ordered:
|
||||
* SSE41 < AVX < AVX2,
|
||||
* AVX2 < AVX512_MIC < AVX512_MIC_4OPS,
|
||||
* AVX2 < AVX512_CORE < AVX512_CORE_VNNI < AVX512_CORE_BF16.
|
||||
* AVX2 < AVX512_CORE < AVX512_CORE_VNNI < AVX512_CORE_BF16 < AVX512_CORE_AMX.
|
||||
|
||||
This feature can also be managed at run-time with the following functions:
|
||||
* @ref dnnl::set_max_cpu_isa function allows changing the ISA at run-time.
|
||||
|
||||
+4
-2
@@ -3379,12 +3379,14 @@ dnnl_status_t DNNL_API dnnl_set_jit_profiling_jitdumpdir(const char *dir);
|
||||
/// The ISAs are only partially ordered:
|
||||
/// - SSE41 < AVX < AVX2,
|
||||
/// - AVX2 < AVX512_MIC < AVX512_MIC_4OPS,
|
||||
/// - AVX2 < AVX512_CORE < AVX512_CORE_VNNI < AVX512_CORE_BF16.
|
||||
/// - AVX2 < AVX512_CORE < AVX512_CORE_VNNI < AVX512_CORE_BF16
|
||||
/// < AVX512_CORE_AMX.
|
||||
///
|
||||
/// @sa @ref dev_guide_cpu_dispatcher_control for more details
|
||||
///
|
||||
/// @param isa Maximal ISA the library should dispatch to. Pass
|
||||
/// #dnnl_cpu_isa_all/#dnnl::cpu_isa::all to remove ISA restrictions.
|
||||
/// #dnnl_cpu_isa_all/#dnnl::cpu_isa::all to remove ISA restrictions
|
||||
/// (except for ISAs with initial support in the library).
|
||||
/// @returns #dnnl_success/#dnnl::status::success on success and a
|
||||
/// #dnnl_invalid_arguments/#dnnl::status::invalid_arguments if the @p isa
|
||||
/// parameter is invalid or the ISA cannot be changed at this time.
|
||||
|
||||
@@ -9921,6 +9921,8 @@ enum class cpu_isa {
|
||||
avx512_core_vnni = dnnl_cpu_isa_avx512_core_vnni,
|
||||
/// @copydoc dnnl_cpu_isa_avx512_core_bf16
|
||||
avx512_core_bf16 = dnnl_cpu_isa_avx512_core_bf16,
|
||||
/// @copydoc dnnl_cpu_isa_avx512_core_amx
|
||||
avx512_core_amx = dnnl_cpu_isa_avx512_core_amx,
|
||||
};
|
||||
|
||||
/// @copydoc dnnl_set_max_cpu_isa()
|
||||
|
||||
@@ -2218,7 +2218,7 @@ typedef struct {
|
||||
|
||||
/// CPU instruction set flags
|
||||
typedef enum {
|
||||
/// Any ISA (no restrictions)
|
||||
/// Any ISA (excepting those listed as initial support)
|
||||
dnnl_cpu_isa_all = 0x0,
|
||||
|
||||
/// Intel Streaming SIMD Extensions 4.1 (Intel SSE4.1)
|
||||
@@ -2251,6 +2251,11 @@ typedef enum {
|
||||
/// for Intel Xeon Scalable processor family
|
||||
/// and Intel Core processor family.
|
||||
dnnl_cpu_isa_avx512_core_bf16 = 0xe7,
|
||||
|
||||
/// Intel AVX-512, Intel DL Boost and bfloat16 support and
|
||||
/// Intel AMX with 8-bit integer and bfloat16 support
|
||||
/// (initial support)
|
||||
dnnl_cpu_isa_avx512_core_amx = 0x3e7,
|
||||
} dnnl_cpu_isa_t;
|
||||
|
||||
/// @} dnnl_api_service
|
||||
|
||||
@@ -104,6 +104,7 @@ bool init_max_cpu_isa() {
|
||||
ELSEIF_HANDLE_CASE(avx512_core);
|
||||
ELSEIF_HANDLE_CASE(avx512_core_vnni);
|
||||
ELSEIF_HANDLE_CASE(avx512_core_bf16);
|
||||
ELSEIF_HANDLE_CASE(avx512_core_amx);
|
||||
|
||||
#undef IF_HANDLE_CASE
|
||||
#undef ELSEIF_HANDLE_CASE
|
||||
@@ -117,11 +118,12 @@ bool init_max_cpu_isa() {
|
||||
struct isa_info_t {
|
||||
isa_info_t(cpu_isa_t aisa) : isa(aisa) {};
|
||||
|
||||
// this converter is needed due to code base uses avx512_common isa which
|
||||
// the library does not expose, so the internal and external enum types
|
||||
// do not coincide.
|
||||
// this converter is needed as code base defines certain ISAs
|
||||
// that the library does not expose (eg avx512_common),
|
||||
// so the internal and external enum types do not coincide.
|
||||
dnnl_cpu_isa_t convert_to_public_enum(void) const {
|
||||
switch (isa) {
|
||||
case avx512_core_amx: return dnnl_cpu_isa_avx512_core_amx;
|
||||
case avx512_core_bf16: return dnnl_cpu_isa_avx512_core_bf16;
|
||||
case avx512_core_vnni: return dnnl_cpu_isa_avx512_core_vnni;
|
||||
case avx512_core: return dnnl_cpu_isa_avx512_core;
|
||||
@@ -136,6 +138,15 @@ struct isa_info_t {
|
||||
|
||||
const char *get_name() const {
|
||||
switch (isa) {
|
||||
case avx512_core_amx:
|
||||
return "Intel AVX-512 with Intel DL Boost and bfloat16 support "
|
||||
"and Intel AMX with bfloat16 and 8-bit integer support";
|
||||
case avx512_core_bf16_amx_bf16:
|
||||
return "Intel AVX-512 with Intel DL Boost and bfloat16 support "
|
||||
"and Intel AMX with bfloat16 support";
|
||||
case avx512_core_bf16_amx_int8:
|
||||
return "Intel AVX-512 with Intel DL Boost and bfloat16 support "
|
||||
"and Intel AMX with 8-bit integer support";
|
||||
case avx512_core_bf16:
|
||||
return "Intel AVX-512 with Intel DL Boost and bfloat16 support";
|
||||
case avx512_core_vnni: return "Intel AVX-512 with Intel DL Boost";
|
||||
@@ -163,6 +174,9 @@ static const isa_info_t get_isa_info_t(void) {
|
||||
// descending order due to mayiuse check
|
||||
#define HANDLE_CASE(cpu_isa) \
|
||||
if (mayiuse(cpu_isa)) return isa_info_t(cpu_isa);
|
||||
HANDLE_CASE(avx512_core_amx);
|
||||
HANDLE_CASE(avx512_core_bf16_amx_bf16);
|
||||
HANDLE_CASE(avx512_core_bf16_amx_int8);
|
||||
HANDLE_CASE(avx512_core_bf16);
|
||||
HANDLE_CASE(avx512_core_vnni);
|
||||
HANDLE_CASE(avx512_core);
|
||||
@@ -209,6 +223,7 @@ status_t set_max_cpu_isa(dnnl_cpu_isa_t isa) {
|
||||
HANDLE_CASE(avx512_core);
|
||||
HANDLE_CASE(avx512_core_vnni);
|
||||
HANDLE_CASE(avx512_core_bf16);
|
||||
HANDLE_CASE(avx512_core_amx);
|
||||
default: return invalid_arguments;
|
||||
}
|
||||
assert(isa_to_set != isa_any);
|
||||
@@ -227,6 +242,64 @@ dnnl_cpu_isa_t get_effective_cpu_isa() {
|
||||
return get_isa_info_t().convert_to_public_enum();
|
||||
}
|
||||
|
||||
namespace amx {
|
||||
|
||||
int get_max_palette() {
|
||||
if (mayiuse(amx_tile)) {
|
||||
unsigned int data[4] = {};
|
||||
const unsigned int &EAX = data[0];
|
||||
|
||||
cpu.getCpuidEx(0x1D, 0, data);
|
||||
return EAX;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_max_tiles(int palette) {
|
||||
if (mayiuse(amx_tile)) {
|
||||
if (palette > get_max_palette() || palette <= 0) return -1;
|
||||
|
||||
unsigned int data[4] = {};
|
||||
const unsigned int &EBX = data[1];
|
||||
cpu.getCpuidEx(0x1D, palette, data);
|
||||
|
||||
return EBX >> 16;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_max_column_bytes(int palette) {
|
||||
if (mayiuse(amx_tile)) {
|
||||
if (palette > get_max_palette() || palette <= 0) return -1;
|
||||
|
||||
unsigned int data[4] = {};
|
||||
const unsigned int &EBX = data[1];
|
||||
cpu.getCpuidEx(0x1D, palette, data);
|
||||
|
||||
return (EBX << 16) >> 16;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_max_rows(int palette) {
|
||||
if (mayiuse(amx_tile)) {
|
||||
if (palette > get_max_palette() || palette <= 0) return -1;
|
||||
|
||||
unsigned int data[4] = {};
|
||||
const unsigned int &ECX = data[2];
|
||||
cpu.getCpuidEx(0x1D, palette, data);
|
||||
|
||||
return (ECX << 16) >> 16;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace amx
|
||||
|
||||
} // namespace x64
|
||||
} // namespace cpu
|
||||
} // namespace impl
|
||||
|
||||
@@ -54,6 +54,9 @@ enum cpu_isa_bit_t : unsigned {
|
||||
avx512_core_bit = 1u << 6,
|
||||
avx512_core_vnni_bit = 1u << 7,
|
||||
avx512_core_bf16_bit = 1u << 8,
|
||||
amx_tile_bit = 1u << 9,
|
||||
amx_int8_bit = 1u << 10,
|
||||
amx_bf16_bit = 1u << 11,
|
||||
};
|
||||
|
||||
enum cpu_isa_t : unsigned {
|
||||
@@ -67,7 +70,14 @@ enum cpu_isa_t : unsigned {
|
||||
avx512_core = avx512_core_bit | avx512_common,
|
||||
avx512_core_vnni = avx512_core_vnni_bit | avx512_core,
|
||||
avx512_core_bf16 = avx512_core_bf16_bit | avx512_core_vnni,
|
||||
isa_all = ~0u,
|
||||
amx_tile = amx_tile_bit,
|
||||
amx_int8 = amx_int8_bit | amx_tile,
|
||||
amx_bf16 = amx_bf16_bit | amx_tile,
|
||||
avx512_core_bf16_amx_int8 = avx512_core_bf16 | amx_int8,
|
||||
avx512_core_bf16_amx_bf16 = avx512_core_bf16 | amx_bf16,
|
||||
avx512_core_amx = avx512_core_bf16 | amx_int8 | amx_bf16,
|
||||
// NOTE: Intel AMX is under initial support and turned off by default
|
||||
isa_all = ~0u & ~amx_tile_bit & ~amx_int8_bit & ~amx_bf16_bit,
|
||||
};
|
||||
|
||||
const char *get_isa_info();
|
||||
@@ -79,6 +89,17 @@ dnnl_cpu_isa_t get_effective_cpu_isa();
|
||||
template <cpu_isa_t>
|
||||
struct cpu_isa_traits {}; /* ::vlen -> 32 (for avx2) */
|
||||
|
||||
// pack struct so it can fit into a single 64-byte cache line
|
||||
#pragma pack(push, 1)
|
||||
struct tileconfig_t {
|
||||
uint8_t palette_id;
|
||||
uint8_t startRow;
|
||||
uint8_t reserved[14];
|
||||
uint16_t cols[16];
|
||||
uint8_t rows[16];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <>
|
||||
struct cpu_isa_traits<isa_all> {
|
||||
static constexpr dnnl_cpu_isa_t user_option_val = dnnl_cpu_isa_all;
|
||||
@@ -152,6 +173,13 @@ struct cpu_isa_traits<avx512_core_bf16> : public cpu_isa_traits<avx512_core> {
|
||||
static constexpr const char *user_option_env = "AVX512_CORE_BF16";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct cpu_isa_traits<avx512_core_amx> {
|
||||
static constexpr dnnl_cpu_isa_t user_option_val
|
||||
= dnnl_cpu_isa_avx512_core_amx;
|
||||
static constexpr const char *user_option_env = "AVX512_CORE_AMX";
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
static Xbyak::util::Cpu cpu;
|
||||
@@ -182,6 +210,18 @@ static inline bool mayiuse(const cpu_isa_t cpu_isa, bool soft = false) {
|
||||
case avx512_core_bf16:
|
||||
return mayiuse(avx512_core_vnni, soft)
|
||||
&& cpu.has(Cpu::tAVX512_BF16);
|
||||
case amx_tile: return cpu.has(Cpu::tAMX_TILE);
|
||||
case amx_int8:
|
||||
return mayiuse(amx_tile, soft) && cpu.has(Cpu::tAMX_INT8);
|
||||
case amx_bf16:
|
||||
return mayiuse(amx_tile, soft) && cpu.has(Cpu::tAMX_BF16);
|
||||
case avx512_core_bf16_amx_int8:
|
||||
return mayiuse(avx512_core_bf16, soft) && mayiuse(amx_int8, soft);
|
||||
case avx512_core_bf16_amx_bf16:
|
||||
return mayiuse(avx512_core_bf16, soft) && mayiuse(amx_bf16, soft);
|
||||
case avx512_core_amx:
|
||||
return mayiuse(avx512_core_bf16_amx_int8, soft)
|
||||
&& mayiuse(avx512_core_bf16_amx_bf16, soft);
|
||||
case isa_any: return true;
|
||||
case isa_all: return false;
|
||||
}
|
||||
@@ -208,9 +248,20 @@ inline bool isa_has_bf16(cpu_isa_t isa) {
|
||||
((isa) == avx512_mic ? prefix STRINGIFY(avx512_mic) : \
|
||||
((isa) == avx512_mic_4ops ? prefix STRINGIFY(avx512_mic_4ops) : \
|
||||
((isa) == avx512_core_bf16 ? prefix STRINGIFY(avx512_core_bf16) : \
|
||||
prefix suffix_if_any))))))))))
|
||||
((isa) == avx512_core_bf16_amx_int8 ? prefix STRINGIFY(avx512_core_bf16_amx_int8) : \
|
||||
((isa) == avx512_core_bf16_amx_bf16 ? prefix STRINGIFY(avx512_core_bf16_amx_bf16) : \
|
||||
prefix suffix_if_any))))))))))))
|
||||
/* clang-format on */
|
||||
|
||||
namespace amx {
|
||||
|
||||
int get_max_palette();
|
||||
int get_max_tiles(int palette);
|
||||
int get_max_column_bytes(int palette);
|
||||
int get_max_rows(int palette);
|
||||
|
||||
} // namespace amx
|
||||
|
||||
} // namespace x64
|
||||
} // namespace cpu
|
||||
} // namespace impl
|
||||
|
||||
@@ -26,8 +26,10 @@ namespace dnnl {
|
||||
|
||||
using namespace impl::cpu::x64;
|
||||
|
||||
const std::set<cpu_isa_t> cpu_isa_all = {sse41, avx, avx2, avx512_mic,
|
||||
avx512_mic_4ops, avx512_core, avx512_core_vnni, avx512_core_bf16};
|
||||
const std::set<cpu_isa_t> cpu_isa_all
|
||||
= {sse41, avx, avx2, avx512_mic, avx512_mic_4ops, avx512_core,
|
||||
avx512_core_vnni, avx512_core_bf16, avx512_core_bf16_amx_int8,
|
||||
avx512_core_bf16_amx_bf16, avx512_core_amx, isa_all};
|
||||
|
||||
struct isa_compat_info {
|
||||
cpu_isa_t this_isa;
|
||||
@@ -52,6 +54,16 @@ static std::map<cpu_isa, isa_compat_info> isa_compatibility_table = {
|
||||
{avx512_core_bf16,
|
||||
{sse41, avx, avx2, avx512_core, avx512_core_vnni,
|
||||
avx512_core_bf16}}},
|
||||
{cpu_isa::avx512_core_amx,
|
||||
{avx512_core_amx,
|
||||
{sse41, avx, avx2, avx512_core, avx512_core_vnni,
|
||||
avx512_core_bf16, avx512_core_bf16_amx_int8,
|
||||
avx512_core_bf16_amx_bf16, avx512_core_amx}}},
|
||||
{cpu_isa::all,
|
||||
{isa_all,
|
||||
{sse41, avx, avx2, avx512_mic, avx512_mic_4ops,
|
||||
avx512_core, avx512_core_vnni, avx512_core_bf16,
|
||||
isa_all}}},
|
||||
};
|
||||
|
||||
class isa_test : public ::testing::TestWithParam<cpu_isa> {
|
||||
@@ -85,6 +97,7 @@ INSTANTIATE_TEST_SUITE_P(TestISACompatibility, isa_test,
|
||||
::testing::Values(cpu_isa::sse41, cpu_isa::avx, cpu_isa::avx2,
|
||||
cpu_isa::avx512_mic, cpu_isa::avx512_mic_4ops,
|
||||
cpu_isa::avx512_core, cpu_isa::avx512_core_vnni,
|
||||
cpu_isa::avx512_core_bf16));
|
||||
cpu_isa::avx512_core_bf16, cpu_isa::avx512_core_amx,
|
||||
cpu_isa::all));
|
||||
|
||||
} // namespace dnnl
|
||||
|
||||
Reference in New Issue
Block a user