working on per-PoolThread context loading and global context loading

This commit is contained in:
Youmu Liu
2026-02-24 18:05:16 +08:00
parent d62e59cb93
commit 7ee9c749e5
12 changed files with 535 additions and 305 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ SN_API SIMDID load_intrinsic_function(void *intrinsic_context, uint64_t id)
if (id) {
simdid.mask = id;
} else {
simdid = sn_get_simd_level();
simdid = sn_get_simd_level_global();
}
sn_intrinsic *context = (sn_intrinsic *)intrinsic_context;
@@ -1,244 +1,244 @@
#include "sn_target.h"
#include "sn_intrinsic.h"
#include "StgSharpNative.h"
static SIMDID global_simdid = { 0 };
#if SN_IS_ARCH(SN_ARCH_X86_64)
#include "sn_intrincontext.x86.h"
#include <immintrin.h>
#include <string.h>
#if defined(_MSC_VER)
#include <intrin.h>
#else
#include <cpuid.h>
#endif
static void get_cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int *edx)
{
#if defined(_MSC_VER)
int regs[4];
__cpuidex(regs, leaf, subleaf);
*eax = regs[0];
*ebx = regs[1];
*ecx = regs[2];
*edx = regs[3];
#else
unsigned int a, b, c, d;
__cpuid_count((unsigned int)leaf, (unsigned int)subleaf, a, b, c, d);
*eax = (int)a;
*ebx = (int)b;
*ecx = (int)c;
*edx = (int)d;
#endif
}
static int xgetbv_has_xmm_ymm(void)
{
#if defined(_MSC_VER)
unsigned __int64 xcr0 = _xgetbv(0);
#else
unsigned long long xcr0 = __builtin_ia32_xgetbv(0);
#endif
return ((xcr0 & 0x6) == 0x6);
}
static int xgetbv_has_avx512_state(void)
{
const unsigned long long mask = (1ull << 0) | (1ull << 1) | (1ull << 2) | (1ull << 5) |
(1ull << 6);
#if defined(_MSC_VER)
unsigned __int64 xcr0 = _xgetbv(0);
#else
unsigned long long xcr0 = __builtin_ia32_xgetbv(0);
#endif
return ((xcr0 & mask) == mask);
}
static int is_intel_dual_avx512(int family, int model)
{
return (family == 6) && (model == 0x55); /* SKX/CLX/CPX */
}
static int is_intel_native_avx512(int family, int model)
{
if (family != 6)
return 0;
switch (model) {
case 0x6A: /* ICX */
case 0x6C: /* ICX stepping */
case 0x8F: /* SPR/EMR */
case 0xCF: /* GNR */
return 1;
default:
return 0;
}
}
SN_API SIMDID SN_DECL sn_get_simd_level_local()
{
SIMDID _simdid = { 0 };
int eax = 0, ebx = 0, ecx = 0, edx = 0;
/* Vendor */
get_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
char vendor[13];
((int *)vendor)[0] = ebx;
((int *)vendor)[1] = edx;
((int *)vendor)[2] = ecx;
vendor[12] = '\0';
const int is_intel = (strcmp(vendor, "GenuineIntel") == 0);
const int is_amd = (strcmp(vendor, "AuthenticAMD") == 0) ||
(strcmp(vendor, "HygonGenuine") == 0);
/* CPUID.1 */
get_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
int family = ((eax >> 8) & 0xF) + ((eax >> 20) & 0xFF0);
int model = ((eax >> 4) & 0xF) | ((eax >> 12) & 0xF0);
int has_sse42 = (ecx & (1 << 20)) != 0;
int has_avx = (ecx & (1 << 28)) != 0;
int has_osxsave = (ecx & (1 << 27)) != 0;
int has_fma = (ecx & (1 << 12)) != 0;
int has_f16c = (ecx & (1 << 29)) != 0;
uint64_t root = SIMDID_PACK_ROOT(SIMDID_ROOT_X86_64);
uint64_t manu = SIMDID_PACK_MANU(is_intel ? SIMDID_MANU_INTEL :
is_amd ? SIMDID_MANU_AMD :
SIMDID_MANU_UNKNOWN);
uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE);
uint64_t avx512_bits = 0;
uint64_t amx_bits = 0;
uint64_t avx_bits = 0;
uint64_t avx10_bits = 0;
/* Baseline main level */
if (has_sse42)
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_SSE);
if (has_avx && has_osxsave && xgetbv_has_xmm_ymm()) {
avx_bits |= SIMDID_AVX;
/* CPUID.7.0 */
get_cpuid(7, 0, &eax, &ebx, &ecx, &edx);
const int has_bmi1 = (ebx & (1 << 3)) != 0;
const int has_bmi2 = (ebx & (1 << 8)) != 0;
const int has_avx2 = (ebx & (1 << 5)) != 0;
const int has_avx512f = (ebx & (1 << 16)) != 0;
const int has_avx512dq = (ebx & (1 << 17)) != 0;
const int has_avx512bw = (ebx & (1 << 30)) != 0;
const int has_avx512vl = (ebx & (1u << 31)) != 0;
const int has_avx512_vnni = (ebx & (1 << 11)) != 0;
const int has_vbmi = (ecx & (1 << 1)) != 0;
const int has_vbmi2 = (ecx & (1 << 6)) != 0;
/* AMX in leaf 7 subleaf 0 EDX bits 24/25/26 — capture before
overwriting regs with subleaf 1 */
const int has_amx_tile = (edx & (1 << 24)) != 0;
const int has_amx_int8 = (edx & (1 << 25)) != 0;
const int has_amx_bf16 = (edx & (1 << 22)) != 0;
/* leaf 7, subleaf 1 for BF16/FP16/AVX10 convergence */
get_cpuid(7, 1, &eax, &ebx, &ecx, &edx);
const int has_bf16 = (eax & (1 << 5)) != 0; /* AVX512_BF16 */
const int has_fp16 = (eax & (1 << 23)) != 0; /* AVX512_FP16 */
const int has_avx10 = (edx & (1 << 19)) != 0; /* AVX10 convergence */
if (has_avx2) {
avx_bits |= SIMDID_AVX2;
if (has_fma)
avx_bits |= SIMDID_AVX_FMA;
if (has_f16c)
avx_bits |= SIMDID_AVX_F16C;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2);
}
if (has_avx512f && xgetbv_has_avx512_state()) {
/* Ensure base subset present */
if (has_avx512bw && has_avx512vl && has_avx512dq) {
avx512_bits |= SIMDID_AVX512_BASE;
}
if (has_avx512_vnni)
avx512_bits |= SIMDID_AVX512_VNNI;
if (has_bf16)
avx512_bits |= SIMDID_AVX512_BF16;
if (has_fp16)
avx512_bits |= SIMDID_AVX512_FP16;
if (has_vbmi)
avx512_bits |= SIMDID_AVX512_VBMI;
if (has_vbmi2)
avx512_bits |= SIMDID_AVX512_VBMI2;
/* impl classification */
const int glue = is_amd || is_intel_dual_avx512(family, model);
const int native512 = is_intel_native_avx512(family, model);
if (glue) {
avx512_bits |= SIMDID_AVX512_IMPL_DUAL;
} else if (native512) {
avx512_bits |= SIMDID_AVX512_IMPL_NATIVE;
} else {
avx512_bits |= SIMDID_AVX512_IMPL_UNKNOWN;
}
/* main level for AVX512 */
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512);
/* AMX promotion if present */
if (has_amx_tile) {
amx_bits |= SIMDID_AMX_TILE;
if (has_amx_int8)
amx_bits |= SIMDID_AMX_INT8;
if (has_amx_bf16)
amx_bits |= SIMDID_AMX_BF16;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AMX);
}
/* AVX10 detection — requires AVX10 convergence bit
(leaf 7 subleaf 1 EDX[19]) and leaf 0x24 */
if (has_avx10) {
int a10_eax = 0, a10_ebx = 0, a10_ecx = 0, a10_edx = 0;
get_cpuid(0x24, 0, &a10_eax, &a10_ebx, &a10_ecx, &a10_edx);
const int avx10_ver = a10_ebx & 0xFF;
if (avx10_ver >= 1) {
avx10_bits |= SIMDID_AVX10 | SIMDID_AVX10_V1;
if (avx10_ver >= 2)
avx10_bits |= SIMDID_AVX10_V2;
if (a10_ebx & (1 << 17))
avx10_bits |= SIMDID_AVX10_256W;
if (a10_ebx & (1 << 18))
avx10_bits |= SIMDID_AVX10_512W;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX10);
}
}
}
}
_simdid.mask = root | manu | main_lvl | SIMDID_PACK_AVX512(avx512_bits) |
SIMDID_PACK_AMX(amx_bits) | SIMDID_PACK_AVX(avx_bits) |
SIMDID_PACK_AVX10(avx10_bits);
return _simdid;
}
SN_API SIMDID SN_DECL sn_get_simd_level()
{
if (global_simdid.mask) {
return global_simdid;
}
global_simdid = sn_get_simd_level_local();
return global_simdid;
}
#else
SIMDID sn_get_simd_level()
{
SIMDID simd_id;
simd_id.mask = 0;
return simd_id; /* non-x86: no SIMD level probing */
}
#endif
#include "sn_target.h"
#include "sn_intrinsic.h"
#include "StgSharpNative.h"
static SIMDID global_simdid = { 0 };
#if SN_IS_ARCH(SN_ARCH_X86_64)
#include "sn_intrincontext.x86.h"
#include <immintrin.h>
#include <string.h>
#if defined(_MSC_VER)
#include <intrin.h>
#else
#include <cpuid.h>
#endif
static void get_cpuid(int leaf, int subleaf, int *eax, int *ebx, int *ecx, int *edx)
{
#if defined(_MSC_VER)
int regs[4];
__cpuidex(regs, leaf, subleaf);
*eax = regs[0];
*ebx = regs[1];
*ecx = regs[2];
*edx = regs[3];
#else
unsigned int a, b, c, d;
__cpuid_count((unsigned int)leaf, (unsigned int)subleaf, a, b, c, d);
*eax = (int)a;
*ebx = (int)b;
*ecx = (int)c;
*edx = (int)d;
#endif
}
static int xgetbv_has_xmm_ymm(void)
{
#if defined(_MSC_VER)
unsigned __int64 xcr0 = _xgetbv(0);
#else
unsigned long long xcr0 = __builtin_ia32_xgetbv(0);
#endif
return ((xcr0 & 0x6) == 0x6);
}
static int xgetbv_has_avx512_state(void)
{
const unsigned long long mask = (1ull << 0) | (1ull << 1) | (1ull << 2) | (1ull << 5) |
(1ull << 6);
#if defined(_MSC_VER)
unsigned __int64 xcr0 = _xgetbv(0);
#else
unsigned long long xcr0 = __builtin_ia32_xgetbv(0);
#endif
return ((xcr0 & mask) == mask);
}
static int is_intel_dual_avx512(int family, int model)
{
return (family == 6) && (model == 0x55); /* SKX/CLX/CPX */
}
static int is_intel_native_avx512(int family, int model)
{
if (family != 6)
return 0;
switch (model) {
case 0x6A: /* ICX */
case 0x6C: /* ICX stepping */
case 0x8F: /* SPR/EMR */
case 0xCF: /* GNR */
return 1;
default:
return 0;
}
}
SN_API SIMDID SN_DECL sn_get_simd_level_local()
{
SIMDID _simdid = { 0 };
int eax = 0, ebx = 0, ecx = 0, edx = 0;
/* Vendor */
get_cpuid(0, 0, &eax, &ebx, &ecx, &edx);
char vendor[13];
((int *)vendor)[0] = ebx;
((int *)vendor)[1] = edx;
((int *)vendor)[2] = ecx;
vendor[12] = '\0';
const int is_intel = (strcmp(vendor, "GenuineIntel") == 0);
const int is_amd = (strcmp(vendor, "AuthenticAMD") == 0) ||
(strcmp(vendor, "HygonGenuine") == 0);
/* CPUID.1 */
get_cpuid(1, 0, &eax, &ebx, &ecx, &edx);
int family = ((eax >> 8) & 0xF) + ((eax >> 20) & 0xFF0);
int model = ((eax >> 4) & 0xF) | ((eax >> 12) & 0xF0);
int has_sse42 = (ecx & (1 << 20)) != 0;
int has_avx = (ecx & (1 << 28)) != 0;
int has_osxsave = (ecx & (1 << 27)) != 0;
int has_fma = (ecx & (1 << 12)) != 0;
int has_f16c = (ecx & (1 << 29)) != 0;
uint64_t root = SIMDID_PACK_ROOT(SIMDID_ROOT_X86_64);
uint64_t manu = SIMDID_PACK_MANU(is_intel ? SIMDID_MANU_INTEL :
is_amd ? SIMDID_MANU_AMD :
SIMDID_MANU_UNKNOWN);
uint64_t main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_NONE);
uint64_t avx512_bits = 0;
uint64_t amx_bits = 0;
uint64_t avx_bits = 0;
uint64_t avx10_bits = 0;
/* Baseline main level */
if (has_sse42)
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_SSE);
if (has_avx && has_osxsave && xgetbv_has_xmm_ymm()) {
avx_bits |= SIMDID_AVX;
/* CPUID.7.0 */
get_cpuid(7, 0, &eax, &ebx, &ecx, &edx);
const int has_bmi1 = (ebx & (1 << 3)) != 0;
const int has_bmi2 = (ebx & (1 << 8)) != 0;
const int has_avx2 = (ebx & (1 << 5)) != 0;
const int has_avx512f = (ebx & (1 << 16)) != 0;
const int has_avx512dq = (ebx & (1 << 17)) != 0;
const int has_avx512bw = (ebx & (1 << 30)) != 0;
const int has_avx512vl = (ebx & (1u << 31)) != 0;
const int has_avx512_vnni = (ebx & (1 << 11)) != 0;
const int has_vbmi = (ecx & (1 << 1)) != 0;
const int has_vbmi2 = (ecx & (1 << 6)) != 0;
/* AMX in leaf 7 subleaf 0 EDX bits 24/25/26 — capture before
overwriting regs with subleaf 1 */
const int has_amx_tile = (edx & (1 << 24)) != 0;
const int has_amx_int8 = (edx & (1 << 25)) != 0;
const int has_amx_bf16 = (edx & (1 << 22)) != 0;
/* leaf 7, subleaf 1 for BF16/FP16/AVX10 convergence */
get_cpuid(7, 1, &eax, &ebx, &ecx, &edx);
const int has_bf16 = (eax & (1 << 5)) != 0; /* AVX512_BF16 */
const int has_fp16 = (eax & (1 << 23)) != 0; /* AVX512_FP16 */
const int has_avx10 = (edx & (1 << 19)) != 0; /* AVX10 convergence */
if (has_avx2) {
avx_bits |= SIMDID_AVX2;
if (has_fma)
avx_bits |= SIMDID_AVX_FMA;
if (has_f16c)
avx_bits |= SIMDID_AVX_F16C;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX2);
}
if (has_avx512f && xgetbv_has_avx512_state()) {
/* Ensure base subset present */
if (has_avx512bw && has_avx512vl && has_avx512dq) {
avx512_bits |= SIMDID_AVX512_BASE;
}
if (has_avx512_vnni)
avx512_bits |= SIMDID_AVX512_VNNI;
if (has_bf16)
avx512_bits |= SIMDID_AVX512_BF16;
if (has_fp16)
avx512_bits |= SIMDID_AVX512_FP16;
if (has_vbmi)
avx512_bits |= SIMDID_AVX512_VBMI;
if (has_vbmi2)
avx512_bits |= SIMDID_AVX512_VBMI2;
/* impl classification */
const int glue = is_amd || is_intel_dual_avx512(family, model);
const int native512 = is_intel_native_avx512(family, model);
if (glue) {
avx512_bits |= SIMDID_AVX512_IMPL_DUAL;
} else if (native512) {
avx512_bits |= SIMDID_AVX512_IMPL_NATIVE;
} else {
avx512_bits |= SIMDID_AVX512_IMPL_UNKNOWN;
}
/* main level for AVX512 */
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX512);
/* AMX promotion if present */
if (has_amx_tile) {
amx_bits |= SIMDID_AMX_TILE;
if (has_amx_int8)
amx_bits |= SIMDID_AMX_INT8;
if (has_amx_bf16)
amx_bits |= SIMDID_AMX_BF16;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AMX);
}
/* AVX10 detection — requires AVX10 convergence bit
(leaf 7 subleaf 1 EDX[19]) and leaf 0x24 */
if (has_avx10) {
int a10_eax = 0, a10_ebx = 0, a10_ecx = 0, a10_edx = 0;
get_cpuid(0x24, 0, &a10_eax, &a10_ebx, &a10_ecx, &a10_edx);
const int avx10_ver = a10_ebx & 0xFF;
if (avx10_ver >= 1) {
avx10_bits |= SIMDID_AVX10 | SIMDID_AVX10_V1;
if (avx10_ver >= 2)
avx10_bits |= SIMDID_AVX10_V2;
if (a10_ebx & (1 << 17))
avx10_bits |= SIMDID_AVX10_256W;
if (a10_ebx & (1 << 18))
avx10_bits |= SIMDID_AVX10_512W;
main_lvl = SIMDID_PACK_MAIN(SIMDID_MAIN_LVL_AVX10);
}
}
}
}
_simdid.mask = root | manu | main_lvl | SIMDID_PACK_AVX512(avx512_bits) |
SIMDID_PACK_AMX(amx_bits) | SIMDID_PACK_AVX(avx_bits) |
SIMDID_PACK_AVX10(avx10_bits);
return _simdid;
}
SN_API SIMDID SN_DECL sn_get_simd_level_global()
{
if (global_simdid.mask) {
return global_simdid;
}
global_simdid = sn_get_simd_level_local();
return global_simdid;
}
#else
SIMDID sn_get_simd_level()
{
SIMDID simd_id;
simd_id.mask = 0;
return simd_id; /* non-x86: no SIMD level probing */
}
#endif
+199
View File
@@ -0,0 +1,199 @@
#include "sn_target.h"
#if SN_IS_ARCH(SN_ARCH_X86_64)
#include "StgSharpNative.h"
#include "sn_intrinsic.h"
#include "sn_intrincontext.x86.h"
/* -----------------------------------------------------------------------
* Field extraction helpers.
*
* SIMDID layout (64 bits, little-endian byte order in make_byte[]):
* [3..0] Root ISA make_byte[0] low nibble
* [7..4] Manufacture make_byte[0] high nibble
* [15..8] MainLevel make_byte[1]
* [31..16] AVX512 Feature make_byte[2..3] (16 bits)
* [39..32] AMX Feature make_byte[4]
* [47..40] AVX Feature make_byte[5]
* [55..48] AVX10 Feature make_byte[6]
* [63..56] uArchHi make_byte[7]
* ----------------------------------------------------------------------- */
#define FIELD_MAIN(id) ((unsigned char)(id).make_byte[1])
#define FIELD_AVX512(id) ((uint16_t)((unsigned char)(id).make_byte[2] | \
((unsigned char)(id).make_byte[3] << 8)))
#define FIELD_AMX(id) ((unsigned char)(id).make_byte[4])
#define FIELD_AVX(id) ((unsigned char)(id).make_byte[5])
#define FIELD_AVX10(id) ((unsigned char)(id).make_byte[6])
#define FIELD_UARCH(id) ((unsigned char)(id).make_byte[7])
/* Portable popcount for a 16-bit value. */
static int popcount16(uint16_t v)
{
int c = 0;
while (v) { v &= v - 1; c++; }
return c;
}
/* Map AVX512_IMPL 2-bit field to a strength ordinal for tie-breaking.
* DUAL(1) => 0 (weakest), UNKNOWN(0) => 1, NATIVE(2) => 2 (strongest) */
static int impl_strength(uint16_t avx512)
{
unsigned impl = (avx512 >> SIMDID_AVX512_IMPL_SHIFT) & 0x3u;
switch (impl) {
case 1: return 0; /* DUAL — glue / downclock risk */
case 0: return 1; /* UNKNOWN — conservatively mid */
case 2: return 2; /* NATIVE — full-width ALU */
default: return 1; /* reserved, treat as unknown */
}
}
/* -----------------------------------------------------------------------
* sn_get_unite_simd
*
* Produce the conservative intersection of two SIMDIDs — the strongest
* capability set that is safe to use on BOTH cores:
* - MainLevel : min (only assume what both cores support)
* - AVX512 features : bitwise AND (IMPL field: pick the weaker one)
* - AMX features : bitwise AND
* - AVX features : bitwise AND
* - AVX10 features : bitwise AND
* - Root / Manu : keep left (must be same arch in practice)
* - uArchHi : min (most conservative policy)
* ----------------------------------------------------------------------- */
SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right)
{
SIMDID out;
out.mask = 0;
/* Root + Manufacture (byte 0): prefer left (same arch assumed) */
unsigned char lb0 = (unsigned char)left.make_byte[0];
unsigned char rb0 = (unsigned char)right.make_byte[0];
out.make_byte[0] = (char)(lb0 ? lb0 : rb0);
/* MainLevel (byte 1): min */
unsigned char lm = FIELD_MAIN(left);
unsigned char rm = FIELD_MAIN(right);
out.make_byte[1] = (char)(lm < rm ? lm : rm);
/* AVX512 features (bytes 2-3): AND all bits, then fix IMPL to weaker */
uint16_t l512 = FIELD_AVX512(left);
uint16_t r512 = FIELD_AVX512(right);
uint16_t merged = l512 & r512;
/* Clear the IMPL field, then set the weaker one */
int ls = impl_strength(l512);
int rs = impl_strength(r512);
unsigned weak_impl = (ls <= rs)
? ((l512 >> SIMDID_AVX512_IMPL_SHIFT) & 0x3u)
: ((r512 >> SIMDID_AVX512_IMPL_SHIFT) & 0x3u);
merged = (merged & ~(uint16_t)SIMDID_AVX512_IMPL_MASK)
| (uint16_t)(weak_impl << SIMDID_AVX512_IMPL_SHIFT);
out.make_byte[2] = (char)(merged & 0xFF);
out.make_byte[3] = (char)((merged >> 8) & 0xFF);
/* AMX (byte 4): AND */
out.make_byte[4] = left.make_byte[4] & right.make_byte[4];
/* AVX (byte 5): AND */
out.make_byte[5] = left.make_byte[5] & right.make_byte[5];
/* AVX10 (byte 6): AND */
out.make_byte[6] = left.make_byte[6] & right.make_byte[6];
/* uArchHi (byte 7): min */
unsigned char lu = FIELD_UARCH(left);
unsigned char ru = FIELD_UARCH(right);
out.make_byte[7] = (char)(lu < ru ? lu : ru);
return out;
}
/* -----------------------------------------------------------------------
* sn_compare_simd
*
* Compare two SIMDIDs by ISA strength. Returns:
* +1 if left is strictly stronger than right
* -1 if left is strictly weaker than right
* 0 if equal
*
* Comparison priority (most significant first):
*
* 1. MainLevel ([15..8])
* Higher value = stronger. This is the primary discriminator:
* NONE < SSE < AVX2 < AVX512 < AMX < AVX10
*
* 2. AVX10 vector width ([55..48])
* Only meaningful when both MainLevel == AVX10.
* 512W > 256W-only. Compared by the full AVX10 byte value since
* width bits are in higher positions than version bits.
*
* 3. AVX512 BASE bit (bit 4 of [31..16])
* Only meaningful when both MainLevel >= AVX512.
* BASE=1 (F+CD+VL+DQ+BW all present) > BASE=0.
*
* 4. AVX512 extension popcount
* Count of set extension bits (VNNI/BF16/FP16/VBMI/VBMI2/AI_RESERVED).
* The IMPL and BASE bits are masked out before counting so they don't
* inflate the extension count.
*
* 5. AVX512 IMPL strength (tie-break, performance hint)
* DUAL(weakest) < UNKNOWN < NATIVE(strongest).
* This is not ISA capability but execution-width risk.
*
* 6. uArchHi (final tie-break)
* Higher value = more specific / stronger policy hint.
* ----------------------------------------------------------------------- */
SN_API int SN_DECL sn_compare_simd(SIMDID left, SIMDID right)
{
/* 1. MainLevel */
unsigned lm = FIELD_MAIN(left);
unsigned rm = FIELD_MAIN(right);
if (lm != rm)
return lm > rm ? 1 : -1;
/* 2. AVX10 width (only when MainLevel == AVX10) */
if (lm >= SIMDID_MAIN_LVL_AVX10) {
unsigned la = FIELD_AVX10(left);
unsigned ra = FIELD_AVX10(right);
if (la != ra)
return la > ra ? 1 : -1;
}
/* 3. AVX512 BASE (only when MainLevel >= AVX512) */
if (lm >= SIMDID_MAIN_LVL_AVX512) {
uint16_t l512 = FIELD_AVX512(left);
uint16_t r512 = FIELD_AVX512(right);
int lb = (l512 & SIMDID_AVX512_BASE) != 0;
int rb = (r512 & SIMDID_AVX512_BASE) != 0;
if (lb != rb)
return lb > rb ? 1 : -1;
/* 4. Extension popcount (mask out BASE + IMPL + reserved low nibble) */
uint16_t ext_mask = (uint16_t)~(SIMDID_AVX512_BASE
| SIMDID_AVX512_IMPL_MASK
| 0x000Fu);
int lp = popcount16(l512 & ext_mask);
int rp = popcount16(r512 & ext_mask);
if (lp != rp)
return lp > rp ? 1 : -1;
/* 5. IMPL strength */
int ls = impl_strength(l512);
int rs = impl_strength(r512);
if (ls != rs)
return ls > rs ? 1 : -1;
}
/* 6. uArchHi (final tie-break) */
unsigned lu = FIELD_UARCH(left);
unsigned ru = FIELD_UARCH(right);
if (lu != ru)
return lu > ru ? 1 : -1;
return 0;
}
#endif
+36 -12
View File
@@ -5,27 +5,51 @@
#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#endif
/* Pin the calling thread to a single logical processor.
* core_id: zero-based logical processor index.
* Silently ignored if core_id is out of range or the OS call fails. */
* core_id >= 0 : bind to that logical processor (global index, across groups).
* core_id < 0 : clear affinity constraint within the current group. */
SN_API void SN_DECL sn_set_thread_affinity(int core_id)
{
if (core_id < 0)
return;
#if SN_IS_OS(SN_OS_WINDOWS)
/* windows.h already included via sn_internal.h */
if (core_id >= 64)
if (core_id < 0) {
/* Query which group the thread currently belongs to */
GROUP_AFFINITY current;
GetThreadGroupAffinity(GetCurrentThread(), &current);
/* Build a full mask for that group's actual core count */
DWORD count = GetActiveProcessorCount(current.Group);
GROUP_AFFINITY ga;
memset(&ga, 0, sizeof(ga));
ga.Group = current.Group;
ga.Mask = (count >= 64) ? ~(KAFFINITY)0
: ((KAFFINITY)1 << count) - 1;
SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL);
return;
DWORD_PTR mask = (DWORD_PTR)1 << core_id;
SetThreadAffinityMask(GetCurrentThread(), mask);
}
WORD group = (WORD)(core_id / 64);
int index = core_id % 64;
DWORD count = GetActiveProcessorCount(group);
if ((DWORD)index >= count)
return;
GROUP_AFFINITY ga;
memset(&ga, 0, sizeof(ga));
ga.Group = group;
ga.Mask = (KAFFINITY)1 << index;
SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL);
#elif SN_IS_OS(SN_OS_LINUX)
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(core_id, &set);
if (core_id < 0) {
CPU_ZERO(&set);
long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
for (long i = 0; i < ncpus; i++)
CPU_SET((int)i, &set);
} else {
CPU_ZERO(&set);
CPU_SET(core_id, &set);
}
pthread_setaffinity_np(pthread_self(), sizeof(set), &set);
#endif
}
}