summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2018-10-30 15:55:22 -0700
committerShentubot <shentubot@google.com>2018-10-30 15:56:12 -0700
commit245d81561b521bb94e3aa88fb704b967b023b0f1 (patch)
tree3f28f86ef977a27ba82b2976536f9f1581462f1c
parent805a27c441c2ca133a3a37dc45f79286b5044a70 (diff)
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
-rw-r--r--pkg/cpuid/cpuid.go12
-rw-r--r--pkg/cpuid/cpuid_parse_test.go99
2 files changed, 101 insertions, 10 deletions
diff --git a/pkg/cpuid/cpuid.go b/pkg/cpuid/cpuid.go
index f4b1db896..c19606898 100644
--- a/pkg/cpuid/cpuid.go
+++ b/pkg/cpuid/cpuid.go
@@ -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",
}
diff --git a/pkg/cpuid/cpuid_parse_test.go b/pkg/cpuid/cpuid_parse_test.go
index 81b06f48c..954ed53b6 100644
--- a/pkg/cpuid/cpuid_parse_test.go
+++ b/pkg/cpuid/cpuid_parse_test.go
@@ -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)
}
}