Check your x86-64 level
A machine’s level is a property of its processor as the operating system reports it. These are the quickest ways to find it out.
Linux: ask the dynamic loader
With glibc 2.33 or later (ldd --version shows the version), the
dynamic loader reports which x86-64 levels it would load optimized
libraries for:
$ /lib64/ld-linux-x86-64.so.2 --help | grep -A4 'glibc-hwcaps directories'
Subdirectories of glibc-hwcaps directories, in priority order:
x86-64-v4
x86-64-v3
x86-64-v2 (supported, searched)
The highest level marked supported is the machine’s level: the
output above is from an x86-64-v2 machine. If no level is marked, the
machine is at the x86-64-v1 baseline.
Linux: run the x86-64-level script
This site’s x86-64-level script works where glibc is
older, and says what is missing for the next level. It reads
/proc/cpuinfo and needs only a POSIX shell. Download it, read it,
then run it:
curl -fsSLO https://x86-64.net/x86-64-level
less x86-64-level
sh x86-64-level -v
x86-64-v2
missing for x86-64-v3: avx avx2 bmi1 bmi2 f16c fma abm movbe xsave
-q prints only the number, for use in scripts. The names in the
output are Linux’s flag names; the level pages map them to
features.
Source of x86-64-level
#!/bin/sh
# x86-64-level: print the x86-64 microarchitecture level (x86-64-v1 to
# x86-64-v4) of this machine's processor, as Linux reports it.
#
# Documentation: https://x86-64.net/check/
# SPDX-License-Identifier: MIT
#
# Usage: x86-64-level [-q] [-v]
# -q print only the level number (1 to 4)
# -v also list the features missing for the next level
#
# X86_64_LEVEL_CPUINFO names a file to read instead of /proc/cpuinfo.
set -eu
# Linux flag names of the features each level adds, following the x86-64
# psABI. OSFXSR and OSXSAVE have no flags; Linux clears the AVX family
# flags when the OS has not enabled XSAVE, so the lists below cover them.
LEVEL1="cmov cx8 fpu fxsr mmx syscall sse sse2"
LEVEL2="cx16 lahf_lm popcnt pni sse4_1 sse4_2 ssse3"
LEVEL3="avx avx2 bmi1 bmi2 f16c fma abm movbe xsave"
LEVEL4="avx512f avx512bw avx512cd avx512dq avx512vl"
quiet=0
verbose=0
for arg in "$@"; do
case $arg in
-q) quiet=1 ;;
-v) verbose=1 ;;
-h | --help)
sed -n '2,13s/^# \{0,1\}//p' "$0"
exit 0
;;
*)
echo "x86-64-level: unknown option: $arg" >&2
exit 2
;;
esac
done
cpuinfo=${X86_64_LEVEL_CPUINFO:-/proc/cpuinfo}
if [ ! -r "$cpuinfo" ]; then
echo "x86-64-level: cannot read $cpuinfo (this script needs Linux)" >&2
exit 1
fi
# All CPUs report the same flags; the first "flags" line is enough.
flags=$(sed -n 's/^flags[[:space:]]*:[[:space:]]*//p' "$cpuinfo" | head -n 1)
if [ -z "$flags" ]; then
echo "x86-64-level: no x86 flags line in $cpuinfo" >&2
exit 1
fi
missing() {
for flag in $1; do
case " $flags " in
*" $flag "*) ;;
*) printf ' %s' "$flag" ;;
esac
done
}
level=0
lack=
for n in 1 2 3 4; do
eval "wanted=\$LEVEL$n"
lack=$(missing "$wanted")
[ -n "$lack" ] && break
level=$n
done
if [ "$level" -eq 0 ]; then
echo "x86-64-level: not even the x86-64 baseline; missing:$lack" >&2
exit 1
fi
if [ "$quiet" -eq 1 ]; then
echo "$level"
else
echo "x86-64-v$level"
fi
if [ "$verbose" -eq 1 ] && [ "$level" -lt 4 ]; then
echo "missing for x86-64-v$((level + 1)):$lack"
fi
Linux: read the flags yourself
Every feature has a flag in /proc/cpuinfo, listed on the level
pages. For example, to see which of the x86-64-v3 flags a processor
has:
grep -m1 -o -w -E 'avx|avx2|bmi1|bmi2|f16c|fma|abm|movbe|xsave' /proc/cpuinfo | sort -u
A few flags are named differently from the feature: SSE3 is pni,
LZCNT is abm, CMPXCHG16B is cx16 and LAHF/SAHF is lahf_lm.
Containers and virtual machines
A container shares the kernel of the machine it runs on, so every method on this page reports that machine’s processor, from inside the container as well as outside it.
A virtual machine is different: the guest sees the processor model its hypervisor presents, which often hides newer features. Checking inside the VM gives the level that software in the VM can use, which may be lower than the host’s. Levels in virtual machines explains how to change the model in QEMU, libvirt, Proxmox, VMware and Hyper-V.
Windows
Microsoft’s Coreinfo
lists the processor’s features. Run coreinfo64 -f and compare the
lines marked * with the level tables: it reports every feature the
levels need, including LAHF-SAHF, CX16, MOVBE, F16C and the
AVX-512 subsets.
PowerShell 7.4 or later can also ask .NET, which reports what both the
processor and Windows support. .NET has no properties for MOVBE, F16C,
CMPXCHG16B or LAHF/SAHF, so the result is a close approximation. Save
this as level.ps1 and run pwsh ./level.ps1:
using namespace System.Runtime.Intrinsics.X86
# PowerShell 7.4 or later. .NET does not report MOVBE, F16C,
# CMPXCHG16B or LAHF/SAHF, so this is a close approximation.
$v2 = [Sse3]::IsSupported -and [Ssse3]::IsSupported -and
[Sse41]::IsSupported -and [Sse42]::IsSupported -and [Popcnt]::IsSupported
$v3 = $v2 -and [Avx2]::IsSupported -and [Bmi1]::IsSupported -and
[Bmi2]::IsSupported -and [Fma]::IsSupported -and [Lzcnt]::IsSupported
$v4 = $v3 -and [Avx512F]::IsSupported -and [Avx512BW]::IsSupported -and
[Avx512CD]::IsSupported -and [Avx512DQ]::IsSupported -and [Avx512F+VL]::IsSupported
if ($v4) { 'x86-64-v4' } elseif ($v3) { 'x86-64-v3' } elseif ($v2) { 'x86-64-v2' } else { 'x86-64-v1' }
macOS
On a Mac with an Intel processor, the kernel lists the processor’s features:
sysctl -n machdep.cpu.features machdep.cpu.leaf7_features machdep.cpu.extfeatures
Compare the names with the level tables. macOS spells a few of them
its own way, for example AVX1.0 for AVX and SSE4.1 for SSE4.1.
From C and C++
GCC 12 and Clang 18 accept the level names in
__builtin_cpu_supports, which checks the running processor and
operating system:
#include <stdio.h>
int main(void)
{
/* GCC 12 or later, Clang 18 or later */
if (__builtin_cpu_supports("x86-64-v4"))
puts("x86-64-v4");
else if (__builtin_cpu_supports("x86-64-v3"))
puts("x86-64-v3");
else if (__builtin_cpu_supports("x86-64-v2"))
puts("x86-64-v2");
else
puts("x86-64-v1");
return 0;
}
This is also how a program built for the baseline can choose a faster code path at run time.