cpu, doc, tests: add AMX ISA utilities

Co-authored-by: Nikita Shustrov <nikita.a.shustrov@intel.com>
This commit is contained in:
Wierschem, Keola
2020-07-01 16:30:12 -07:00
co-authored by Nikita Shustrov
parent 8192cab514
commit 1ec78a431d
9 changed files with 173 additions and 15 deletions
+5 -1
View File
@@ -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
+5
View File
@@ -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
View File
@@ -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.
+2
View File
@@ -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()
+6 -1
View File
@@ -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
+76 -3
View File
@@ -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
+53 -2
View File
@@ -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
+16 -3
View File
@@ -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