Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/tests_archdetect.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ jobs:
strategy:
matrix:
proc_cpuinfo:
- x86_64/intel/graniterapids/AWS-Rocky9-6975PC
- x86_64/intel/graniterapids/Azure-Ubuntu24-6973P-C
- x86_64/intel/haswell/archspec-linux-E5-2680-v3
- x86_64/intel/sapphirerapids/AWS-Rocky8-8488C
- x86_64/intel/skylake_avx512/archspec-linux-6132
Expand Down Expand Up @@ -50,6 +52,9 @@ jobs:
export EESSI_MACHINE_TYPE=${{matrix.proc_cpuinfo}}
export EESSI_MACHINE_TYPE=${EESSI_MACHINE_TYPE%%/*}
export EESSI_PROC_CPUINFO=./tests/archdetect/${{matrix.proc_cpuinfo}}.cpuinfo
if [[ -f ./tests/archdetect/${{matrix.proc_cpuinfo}}.cpu_features ]]; then
export EESSI_CPU_FEATURES_FILE=./tests/archdetect/${{matrix.proc_cpuinfo}}.cpu_features
fi
# check that printing of best match works correctly
CPU_ARCH=$(./init/eessi_archdetect.sh cpupath)
if [[ $CPU_ARCH == "$( cat ./tests/archdetect/${{matrix.proc_cpuinfo}}.output )" ]]; then
Expand Down
19 changes: 10 additions & 9 deletions init/arch_specs/eessi_arch_x86.spec
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# x86_64 CPU architecture specifications
# The overview at https://github.com/InstLatx64/InstLatX64_Misc/tree/main/SIMD_Euler may be helpful in defining this list
# Software path in EESSI | Vendor ID | List of defining CPU features
"x86_64/intel/haswell" "GenuineIntel" "avx2 fma" # Intel Haswell, Broadwell
"x86_64/intel/skylake_avx512" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl" # Intel Skylake
"x86_64/intel/cascadelake" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_vnni" # Intel Cascade Lake
"x86_64/intel/icelake" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_vnni avx512_vbmi2" # Intel Icelake Lake
"x86_64/intel/sapphirerapids" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_bf16 amx_tile" # Intel Sapphire/Emerald Rapids
"x86_64/amd/zen2" "AuthenticAMD" "avx2 fma" # AMD Rome
"x86_64/amd/zen3" "AuthenticAMD" "avx2 fma vaes" # AMD Milan, Milan-X
"x86_64/amd/zen4" "AuthenticAMD" "avx2 fma vaes avx512f avx512ifma" # AMD Genoa, Genoa-X
"x86_64/amd/zen5" "AuthenticAMD" "avx2 fma vaes avx512f avx512ifma avx512_vp2intersect avx_vnni movdiri" # AMD Turin
"x86_64/intel/haswell" "GenuineIntel" "avx2 fma" # Intel Haswell, Broadwell
"x86_64/intel/skylake_avx512" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl" # Intel Skylake
"x86_64/intel/cascadelake" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_vnni" # Intel Cascade Lake
"x86_64/intel/icelake" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_vnni avx512_vbmi2" # Intel Icelake Lake
"x86_64/intel/sapphirerapids" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_bf16 amx_tile" # Intel Sapphire/Emerald Rapids
"x86_64/intel/graniterapids" "GenuineIntel" "avx2 fma avx512f avx512bw avx512cd avx512dq avx512vl avx512_bf16 amx_tile amx_fp16" # Granite
"x86_64/amd/zen2" "AuthenticAMD" "avx2 fma" # AMD Rome
"x86_64/amd/zen3" "AuthenticAMD" "avx2 fma vaes" # AMD Milan, Milan-X
"x86_64/amd/zen4" "AuthenticAMD" "avx2 fma vaes avx512f avx512ifma" # AMD Genoa, Genoa-X
"x86_64/amd/zen5" "AuthenticAMD" "avx2 fma vaes avx512f avx512ifma avx512_vp2intersect avx_vnni movdiri" # AMD Turin
80 changes: 75 additions & 5 deletions init/eessi_archdetect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ LOG_LEVEL="WARN"
# Default result type is a best match
CPUPATH_RESULT="best"

# map CPU flag names from cpu_features to the ones used in /proc/cpuinfo
declare -A cpu_flags_name_map=(
[fma3]=fma
[avx512bitalg]=avx512_bitalg
[avx512vbmi2]=avx512_vbmi2
[avx512vnni]=avx512_vnni
[avx512vpopcntdq]=avx512_vpopcntdq
[sha]=sha_ni
)

timestamp () {
date "+%Y-%m-%d %H:%M:%S"
}
Expand Down Expand Up @@ -70,6 +80,50 @@ get_cpuinfo(){
grep -i "$cpuinfo_pattern" ${EESSI_PROC_CPUINFO:-/proc/cpuinfo} | tail -n 1 | sed "s/$cpuinfo_pattern//i"
}

# CPU specification of host system as reported by cpu_features
get_cpu_features(){
# Return the value from list_cpu_features for the matching key
# 1: string with key pattern

[ -z "$1" ] && log "ERROR" "get_cpu_features: missing key pattern in argument list"
cpu_features_pattern="^${1}\s*:\s*"

if [ ! -z ${EESSI_CPU_FEATURES_FILE} ]; then
cpu_features_output=$(cat ${EESSI_CPU_FEATURES_FILE})
elif command -v "list_cpu_features" >/dev/null 2>&1; then
cpu_features_output=$(list_cpu_features)
else
log "DEBUG" "cpu_features cannot be found"
return 1
fi

# /proc/cpuinfo uses space-separated flags and uses different names for some flags,
# so we reformat and rename things a bit here to make it easier to do the comparisons
cpu_features_reformatted=$(
while IFS= read -r line; do
if [[ $line =~ ^(flags[[:space:]]*:[[:space:]]*)(.*)$ ]]; then
prefix=${BASH_REMATCH[1]}
flags=${BASH_REMATCH[2]}

new_flags=""
IFS=',' read -ra flag_array <<< "$flags"

for flag in "${flag_array[@]}"; do
new_flags+=" ${cpu_flags_name_map[$flag]:-$flag}"
done

printf '%s%s\n' "$prefix" "${new_flags# }"
else
printf '%s\n' "$line"
fi
done <<< "${cpu_features_output}"
)

# case insensitive match of key pattern and delete key pattern from result
echo "${cpu_features_reformatted}" | grep -i "$cpu_features_pattern" | tail -n 1 | sed "s/$cpu_features_pattern//i"
return 0
}

check_allinfirst(){
# Return true if all given arguments after the first are found in the first one
# 1: reference string of space separated values
Expand Down Expand Up @@ -168,26 +222,42 @@ cpupath(){
# each flag in this CPU specification must be found in the list of flags of the host
check_allinfirst "${cpu_flags[*]}" ${arch_spec[2]} && best_arch_match=${arch_spec[0]} && \
all_arch_matches="$best_arch_match:$all_arch_matches" && \
log "DEBUG" "cpupath: host CPU best match updated to $best_arch_match"
log "DEBUG" "cpupath: host CPU best match updated to $best_arch_match"
fi
done

# Some Intel microarchitectures are flag-indistinguishable from an older one because their
# new features are not exposed in /proc/cpuinfo. Granite Rapids (Xeon 6) shows the exact same
# visible flags as Sapphire/Emerald Rapids (its extras like amx_fp16 are hidden by the kernel),
# so the flag match above lands on 'sapphirerapids'. Refine using the CPU model number - the
# only reliable discriminator on Linux. If no dedicated graniterapids subdir is shipped yet,
# downstream subdir resolution falls back to the next entry in the chain, so prepending is safe.
# so the flag match above lands on 'sapphirerapids'.
# Refine using the list_cpu_features tool from Google's cpu_features if available,
# and otherwise use the CPU model number.
if [ "${best_arch_match}" == "x86_64/intel/sapphirerapids" ]; then
local cpu_family=$(get_cpuinfo "cpu[ _]family")
local cpu_model=$(get_cpuinfo "model")
log "DEBUG" "cpupath: refining Sapphire Rapids match (family='$cpu_family', model='$cpu_model')"
if cpu_features_flags=$(get_cpu_features "$cpu_flag_tag"); then
log "DEBUG" "Flags reported by list_cpu_features: ${cpu_features_flags}"
# Now that we have a (possibly) changed set of flags, reset the results to their defaults and
# reiterate over the supported CPU specifications to find the best match for host CPU.
# Order of the specifications matters, the last one to match will be selected
local best_arch_match="$machine_type/generic"
local all_arch_matches=$best_arch_match
for arch in "${cpu_arch_spec[@]}"; do
eval "arch_spec=$arch"
if [ "${cpu_vendor}x" == "${arch_spec[1]}x" ]; then
# each flag in this CPU specification must be found in the list of flags of the host
check_allinfirst "${cpu_features_flags[*]}" ${arch_spec[2]} && best_arch_match=${arch_spec[0]} && \
all_arch_matches="$best_arch_match:$all_arch_matches" && \
log "DEBUG" "cpupath: host CPU best match updated to $best_arch_match"
fi
done
# Intel family 6 model numbers below come from the kernel's authoritative table
# arch/x86/include/asm/intel-family.h (what the kernel itself uses for model dispatch):
# INTEL_GRANITERAPIDS_X = IFM(6, 0xAD) -> family 6, model 173 (Granite Rapids-SP/AP)
# INTEL_GRANITERAPIDS_D = IFM(6, 0xAE) -> family 6, model 174 (Granite Rapids-D)
# (cf. INTEL_SAPPHIRERAPIDS_X = 0x8F/143, INTEL_EMERALDRAPIDS_X = 0xCF/207)
if [ "${cpu_family}" == "6" ] && { [ "${cpu_model}" == "173" ] || [ "${cpu_model}" == "174" ]; }; then
elif [ "${cpu_family}" == "6" ] && { [ "${cpu_model}" == "173" ] || [ "${cpu_model}" == "174" ]; }; then
best_arch_match="x86_64/intel/graniterapids"
all_arch_matches="$best_arch_match:$all_arch_matches"
log "DEBUG" "cpupath: model $cpu_model identifies Granite Rapids; best match upgraded to $best_arch_match"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x86_64/intel/graniterapids:x86_64/intel/sapphirerapids:x86_64/intel/icelake:x86_64/intel/cascadelake:x86_64/intel/skylake_avx512:x86_64/intel/haswell:x86_64/generic
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
arch : x86
brand : Intel(R) Xeon(R) 6975P-C
family : 6 (0x06)
model : 173 (0xAD)
stepping : 1 (0x01)
uarch : X86_UNKNOWN
flags : adx,aes,amx_bf16,amx_fp16,amx_int8,amx_tile,avx,avx2,avx512_bf16,avx512_fp16,avx512_second_fma,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avx_vnni,bmi1,bmi2,clflushopt,clfsh,clwb,cx16,cx8,erms,f16c,fma3,fpu,fs_rep_cmpsb_scasb,fs_rep_stosb,fz_rep_movsb,gfni,lzcnt,mmx,movbe,movdir64b,movdiri,pclmulqdq,popcnt,rdrnd,rdseed,sha,ss,sse,sse2,sse3,sse4_1,sse4_2,ssse3,tsc,vaes,vpclmulqdq
cache_info : {"level":1,"cache_type":"data","cache_size":49152,"ways":12,"line_size":64,"tlb_entries":64,"partitioning":1},{"level":1,"cache_type":"instruction","cache_size":65536,"ways":16,"line_size":64,"tlb_entries":64,"partitioning":1},{"level":2,"cache_type":"unified","cache_size":2097152,"ways":16,"line_size":64,"tlb_entries":2048,"partitioning":1},{"level":3,"cache_type":"unified","cache_size":503316480,"ways":16,"line_size":64,"tlb_entries":491520,"partitioning":1}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 173
model name : Intel(R) Xeon(R) 6975P-C
stepping : 1
microcode : 0x1000434
cpu MHz : 2700.000
cache size : 491520 KB
physical id : 0
siblings : 16
core id : 0
cpu cores : 8
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 36
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid bus_lock_detect cldemote movdiri movdir64b md_clear serialize amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs bhi spectre_v2_user
bogomips : 5400.00
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management:
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x86_64/intel/graniterapids
Loading