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:
Michael Pratt 2018-10-30 15:55:22 -07:00 committed by Shentubot
parent 805a27c441
commit 245d81561b
2 changed files with 101 additions and 10 deletions

View File

@ -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",
}

View File

@ -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)
}
}