#!/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