summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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)
}
}