Clean up cpuid_parse_test
Actually parse flags from cpuinfo to avoid mistakenly matching substrings in cpuinfo that happen to match a flags. Some features were only exposed in recent versions of Linux. Don't require them to appear in cpuinfo on old versions of Linux. Move PREFETCHWT1 back to parse only features. It isn't actually exposed in Linux yet. Move SDBG to shown features. It has been visible since Linux 4.3. PiperOrigin-RevId: 219381731 Change-Id: Ied7c0ee7c8a9879683e81933de56c9074b01108f
This commit is contained in:
parent
805a27c441
commit
245d81561b
|
@ -274,6 +274,7 @@ var x86FeatureStrings = map[Feature]string{
|
|||
X86FeatureTM2: "tm2",
|
||||
X86FeatureSSSE3: "ssse3",
|
||||
X86FeatureCNXTID: "cid",
|
||||
X86FeatureSDBG: "sdbg",
|
||||
X86FeatureFMA: "fma",
|
||||
X86FeatureCX16: "cx16",
|
||||
X86FeatureXTPR: "xtpr",
|
||||
|
@ -352,10 +353,9 @@ var x86FeatureStrings = map[Feature]string{
|
|||
X86FeatureAVX512VL: "avx512vl",
|
||||
|
||||
// Block 3.
|
||||
X86FeaturePREFETCHWT1: "prefetchwt1",
|
||||
X86FeatureAVX512VBMI: "avx512vbmi",
|
||||
X86FeatureUMIP: "umip",
|
||||
X86FeaturePKU: "pku",
|
||||
X86FeatureAVX512VBMI: "avx512vbmi",
|
||||
X86FeatureUMIP: "umip",
|
||||
X86FeaturePKU: "pku",
|
||||
|
||||
// Block 4.
|
||||
X86FeatureXSAVEOPT: "xsaveopt",
|
||||
|
@ -405,7 +405,6 @@ var x86FeatureStrings = map[Feature]string{
|
|||
// flags, but will not get printed out in /proc/cpuinfo.
|
||||
var x86FeatureParseOnlyStrings = map[Feature]string{
|
||||
// Block 0.
|
||||
X86FeatureSDBG: "sdbg",
|
||||
X86FeatureOSXSAVE: "osxsave",
|
||||
|
||||
// Block 2.
|
||||
|
@ -414,6 +413,9 @@ var x86FeatureParseOnlyStrings = map[Feature]string{
|
|||
X86FeatureIPT: "pt",
|
||||
X86FeatureCLFLUSHOPT: "clfushopt",
|
||||
|
||||
// Block 3.
|
||||
X86FeaturePREFETCHWT1: "prefetchwt1",
|
||||
|
||||
// Block 4.
|
||||
X86FeatureXSAVES: "xsaves",
|
||||
}
|
||||
|
|
|
@ -15,23 +15,112 @@
|
|||
package cpuid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHostFeatureFlags ensures that package cpuid recognizes all features
|
||||
// present on this host.
|
||||
func kernelVersion() (int, int, error) {
|
||||
var u syscall.Utsname
|
||||
if err := syscall.Uname(&u); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
var r string
|
||||
for _, b := range u.Release {
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
r += string(b)
|
||||
}
|
||||
|
||||
s := strings.Split(r, ".")
|
||||
if len(s) < 2 {
|
||||
return 0, 0, fmt.Errorf("kernel release missing major and minor component: %s", r)
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(s[0])
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("error parsing major version %q in %q: %v", s[0], r, err)
|
||||
}
|
||||
|
||||
minor, err := strconv.Atoi(s[1])
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("error parsing minor version %q in %q: %v", s[1], r, err)
|
||||
}
|
||||
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
// TestHostFeatureFlags tests that all features detected by HostFeatureSet are
|
||||
// on the host.
|
||||
//
|
||||
// It does *not* verify that all features reported by the host are detected by
|
||||
// HostFeatureSet.
|
||||
//
|
||||
// i.e., test that HostFeatureSet is a subset of the host features.
|
||||
func TestHostFeatureFlags(t *testing.T) {
|
||||
cpuinfoBytes, _ := ioutil.ReadFile("/proc/cpuinfo")
|
||||
cpuinfo := string(cpuinfoBytes)
|
||||
t.Logf("Host cpu info:\n%s", cpuinfo)
|
||||
|
||||
for f := range HostFeatureSet().Set {
|
||||
if f.flagString(false) == "" {
|
||||
major, minor, err := kernelVersion()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to parse kernel version: %v", err)
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`(?m)^flags\s+: (.*)$`)
|
||||
m := re.FindStringSubmatch(cpuinfo)
|
||||
if len(m) != 2 {
|
||||
t.Fatalf("Unable to extract flags from %q", cpuinfo)
|
||||
}
|
||||
|
||||
cpuinfoFlags := make(map[string]struct{})
|
||||
for _, f := range strings.Split(m[1], " ") {
|
||||
cpuinfoFlags[f] = struct{}{}
|
||||
}
|
||||
|
||||
fs := HostFeatureSet()
|
||||
|
||||
// All features have a string and appear in host cpuinfo.
|
||||
for f := range fs.Set {
|
||||
name := f.flagString(false)
|
||||
if name == "" {
|
||||
t.Errorf("Non-parsable feature: %v", f)
|
||||
}
|
||||
if s := f.flagString(true); !strings.Contains(cpuinfo, s) {
|
||||
|
||||
// Special cases not consistently visible. We don't mind if
|
||||
// they are exposed in earlier versions.
|
||||
switch {
|
||||
// Block 0.
|
||||
case f == X86FeatureSDBG && (major < 4 || major == 4 && minor < 3):
|
||||
// SDBG only exposed in
|
||||
// b1c599b8ff80ea79b9f8277a3f9f36a7b0cfedce (4.3).
|
||||
continue
|
||||
// Block 3.
|
||||
case f == X86FeatureAVX512VBMI && (major < 4 || major == 4 && minor < 10):
|
||||
// AVX512VBMI only exposed in
|
||||
// a8d9df5a509a232a959e4ef2e281f7ecd77810d6 (4.10).
|
||||
continue
|
||||
case f == X86FeatureUMIP && (major < 4 || major == 4 && minor < 15):
|
||||
// UMIP only exposed in
|
||||
// 3522c2a6a4f341058b8291326a945e2a2d2aaf55 (4.15).
|
||||
continue
|
||||
case f == X86FeaturePKU && (major < 4 || major == 4 && minor < 9):
|
||||
// PKU only exposed in dfb4a70f20c5b3880da56ee4c9484bdb4e8f1e65
|
||||
// (4.9).
|
||||
continue
|
||||
}
|
||||
|
||||
hidden := f.flagString(true) == ""
|
||||
_, ok := cpuinfoFlags[name]
|
||||
if hidden && ok {
|
||||
t.Errorf("Unexpectedly hidden flag: %v", f)
|
||||
} else if !hidden && !ok {
|
||||
t.Errorf("Non-native flag: %v", f)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue