Commit 3e0227f6 authored by Martin Möhrmann's avatar Martin Möhrmann

internal/cpu: add invalid option warnings and support to enable cpu features

This CL adds the ability to enable the cpu feature FEATURE by specifying
FEATURE=on in GODEBUGCPU. Syntax support to enable cpu features is useful
in combination with a preceeding all=off to disable all but some specific
cpu features. Example:

GODEBUGCPU=all=off,sse3=on

This CL implements printing of warnings for invalid GODEBUGCPU settings:
- requests enabling features that are not supported with the current CPU
- specifying values different than 'on' or 'off' for a feature
- settings for unkown cpu feature names

Updates #27218

Change-Id: Ic13e5c4c35426a390c50eaa4bd2a408ef2ee21be
Reviewed-on: https://go-review.googlesource.com/c/141800
Run-TryBot: Martin Möhrmann <moehrmann@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent f81d73e8
......@@ -153,16 +153,18 @@ var options []option
// Option names should be lower case. e.g. avx instead of AVX.
type option struct {
Name string
Feature *bool
Name string
Feature *bool
Specified bool // Stores if feature value was specified in GODEBUGCPU.
Enable bool // Stores if feature should be enabled.
}
// processOptions disables CPU feature values based on the parsed env string.
// The env string is expected to be of the form feature1=off,feature2=off...
// processOptions enables or disables CPU feature values based on the parsed env string.
// The env string is expected to be of the form feature1=value1,feature2=value2...
// where feature names is one of the architecture specifc list stored in the
// cpu packages options variable. If env contains all=off then all capabilities
// referenced through the options variable are disabled. Other feature
// names and values other than 'off' are silently ignored.
// cpu packages options variable and values are either 'on' or 'off'.
// If env contains all=off then all cpu features referenced through the options
// variable are disabled. Other feature names and values result in warning messages.
func processOptions(env string) {
field:
for env != "" {
......@@ -175,26 +177,52 @@ field:
}
i = indexByte(field, '=')
if i < 0 {
print("GODEBUGCPU: no value specified for \"", field, "\"\n")
continue
}
key, value := field[:i], field[i+1:]
// Only allow turning off CPU features by specifying 'off'.
if value == "off" {
if key == "all" {
for _, v := range options {
*v.Feature = false
}
return
} else {
for _, v := range options {
if v.Name == key {
*v.Feature = false
continue field
}
}
var enable bool
switch value {
case "on":
enable = true
case "off":
enable = false
default:
print("GODEBUGCPU: value \"", value, "\" not supported for option ", key, "\n")
continue field
}
if key == "all" {
for i := range options {
options[i].Specified = true
options[i].Enable = enable
}
continue field
}
for i := range options {
if options[i].Name == key {
options[i].Specified = true
options[i].Enable = enable
continue field
}
}
print("GODEBUGCPU: unknown cpu feature \"", key, "\"\n")
}
for _, o := range options {
if !o.Specified {
continue
}
if o.Enable && !*o.Feature {
print("GODEBUGCPU: can not enable \"", o.Name, "\", missing hardware support\n")
continue
}
*o.Feature = o.Enable
}
}
......
......@@ -21,8 +21,8 @@ const (
func doinit() {
options = []option{
{"vfpv4", &ARM.HasVFPv4},
{"idiva", &ARM.HasIDIVA},
{Name: "vfpv4", Feature: &ARM.HasVFPv4},
{Name: "idiva", Feature: &ARM.HasIDIVA},
}
// HWCAP feature bits
......
......@@ -42,32 +42,32 @@ const (
func doinit() {
options = []option{
{"evtstrm", &ARM64.HasEVTSTRM},
{"aes", &ARM64.HasAES},
{"pmull", &ARM64.HasPMULL},
{"sha1", &ARM64.HasSHA1},
{"sha2", &ARM64.HasSHA2},
{"crc32", &ARM64.HasCRC32},
{"atomics", &ARM64.HasATOMICS},
{"fphp", &ARM64.HasFPHP},
{"asimdhp", &ARM64.HasASIMDHP},
{"cpuid", &ARM64.HasCPUID},
{"asimdrdm", &ARM64.HasASIMDRDM},
{"jscvt", &ARM64.HasJSCVT},
{"fcma", &ARM64.HasFCMA},
{"lrcpc", &ARM64.HasLRCPC},
{"dcpop", &ARM64.HasDCPOP},
{"sha3", &ARM64.HasSHA3},
{"sm3", &ARM64.HasSM3},
{"sm4", &ARM64.HasSM4},
{"asimddp", &ARM64.HasASIMDDP},
{"sha512", &ARM64.HasSHA512},
{"sve", &ARM64.HasSVE},
{"asimdfhm", &ARM64.HasASIMDFHM},
{Name: "evtstrm", Feature: &ARM64.HasEVTSTRM},
{Name: "aes", Feature: &ARM64.HasAES},
{Name: "pmull", Feature: &ARM64.HasPMULL},
{Name: "sha1", Feature: &ARM64.HasSHA1},
{Name: "sha2", Feature: &ARM64.HasSHA2},
{Name: "crc32", Feature: &ARM64.HasCRC32},
{Name: "atomics", Feature: &ARM64.HasATOMICS},
{Name: "fphp", Feature: &ARM64.HasFPHP},
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
{Name: "cpuid", Feature: &ARM64.HasCPUID},
{Name: "asimdrdm", Feature: &ARM64.HasASIMDRDM},
{Name: "jscvt", Feature: &ARM64.HasJSCVT},
{Name: "fcma", Feature: &ARM64.HasFCMA},
{Name: "lrcpc", Feature: &ARM64.HasLRCPC},
{Name: "dcpop", Feature: &ARM64.HasDCPOP},
{Name: "sha3", Feature: &ARM64.HasSHA3},
{Name: "sm3", Feature: &ARM64.HasSM3},
{Name: "sm4", Feature: &ARM64.HasSM4},
{Name: "asimddp", Feature: &ARM64.HasASIMDDP},
{Name: "sha512", Feature: &ARM64.HasSHA512},
{Name: "sve", Feature: &ARM64.HasSVE},
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM},
// These capabilities should always be enabled on arm64:
// {"fp", &ARM64.HasFP},
// {"asimd", &ARM64.HasASIMD},
// {Name: "fp", Feature: &ARM64.HasFP},
// {Name: "asimd", Feature: &ARM64.HasASIMD},
}
// HWCAP feature bits
......
......@@ -34,17 +34,17 @@ const (
func doinit() {
options = []option{
{"htm", &PPC64.HasHTM},
{"htmnosc", &PPC64.HasHTMNOSC},
{"darn", &PPC64.HasDARN},
{"scv", &PPC64.HasSCV},
{Name: "htm", Feature: &PPC64.HasHTM},
{Name: "htmnosc", Feature: &PPC64.HasHTMNOSC},
{Name: "darn", Feature: &PPC64.HasDARN},
{Name: "scv", Feature: &PPC64.HasSCV},
// These capabilities should always be enabled on ppc64 and ppc64le:
// {"vmx", &PPC64.HasVMX},
// {"dfp", &PPC64.HasDFP},
// {"vsx", &PPC64.HasVSX},
// {"isel", &PPC64.HasISEL},
// {"vcrypto", &PPC64.HasVCRYPTO},
// {Name: "vmx", Feature: &PPC64.HasVMX},
// {Name: "dfp", Feature: &PPC64.HasDFP},
// {Name: "vsx", Feature: &PPC64.HasVSX},
// {Name: "isel", Feature: &PPC64.HasISEL},
// {Name: "vcrypto", Feature: &PPC64.HasVCRYPTO},
}
// HWCAP feature bits
......
......@@ -107,14 +107,14 @@ func klmdQuery() queryResult
func doinit() {
options = []option{
{"zarch", &S390X.HasZArch},
{"stfle", &S390X.HasSTFLE},
{"ldisp", &S390X.HasLDisp},
{"msa", &S390X.HasMSA},
{"eimm", &S390X.HasEImm},
{"dfp", &S390X.HasDFP},
{"etf3eh", &S390X.HasETF3Enhanced},
{"vx", &S390X.HasVX},
{Name: "zarch", Feature: &S390X.HasZArch},
{Name: "stfle", Feature: &S390X.HasSTFLE},
{Name: "ldisp", Feature: &S390X.HasLDisp},
{Name: "msa", Feature: &S390X.HasMSA},
{Name: "eimm", Feature: &S390X.HasEImm},
{Name: "dfp", Feature: &S390X.HasDFP},
{Name: "etf3eh", Feature: &S390X.HasETF3Enhanced},
{Name: "vx", Feature: &S390X.HasVX},
}
aes := []function{aes128, aes192, aes256}
......
......@@ -30,7 +30,10 @@ func runDebugOptionsTest(t *testing.T, test string, options string) {
cmd.Env = append(cmd.Env, env)
output, err := cmd.CombinedOutput()
got := strings.TrimSpace(string(output))
lines := strings.Fields(string(output))
lastline := lines[len(lines)-1]
got := strings.TrimSpace(lastline)
want := "PASS"
if err != nil || got != want {
t.Fatalf("%s with %s: want %s, got %v", test, env, want, got)
......
......@@ -40,23 +40,23 @@ const (
func doinit() {
options = []option{
{"adx", &X86.HasADX},
{"aes", &X86.HasAES},
{"avx", &X86.HasAVX},
{"avx2", &X86.HasAVX2},
{"bmi1", &X86.HasBMI1},
{"bmi2", &X86.HasBMI2},
{"erms", &X86.HasERMS},
{"fma", &X86.HasFMA},
{"pclmulqdq", &X86.HasPCLMULQDQ},
{"popcnt", &X86.HasPOPCNT},
{"sse3", &X86.HasSSE3},
{"sse41", &X86.HasSSE41},
{"sse42", &X86.HasSSE42},
{"ssse3", &X86.HasSSSE3},
{Name: "adx", Feature: &X86.HasADX},
{Name: "aes", Feature: &X86.HasAES},
{Name: "avx", Feature: &X86.HasAVX},
{Name: "avx2", Feature: &X86.HasAVX2},
{Name: "bmi1", Feature: &X86.HasBMI1},
{Name: "bmi2", Feature: &X86.HasBMI2},
{Name: "erms", Feature: &X86.HasERMS},
{Name: "fma", Feature: &X86.HasFMA},
{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
{Name: "popcnt", Feature: &X86.HasPOPCNT},
{Name: "sse3", Feature: &X86.HasSSE3},
{Name: "sse41", Feature: &X86.HasSSE41},
{Name: "sse42", Feature: &X86.HasSSE42},
{Name: "ssse3", Feature: &X86.HasSSSE3},
// sse2 set as last element so it can easily be removed again. See code below.
{"sse2", &X86.HasSSE2},
{Name: "sse2", Feature: &X86.HasSSE2},
}
// Remove sse2 from options on amd64(p32) because SSE2 is a mandatory feature for these GOARCHs.
......
......@@ -45,3 +45,20 @@ func TestSSE2DebugOption(t *testing.T) {
t.Errorf("X86.HasSSE2 on %s expected %v, got %v", runtime.GOARCH, want, got)
}
}
func TestDisableSSE3(t *testing.T) {
runDebugOptionsTest(t, "TestSSE3DebugOption", "sse3=off")
}
func TestSSE3DebugOption(t *testing.T) {
MustHaveDebugOptionsSupport(t)
if os.Getenv("GODEBUGCPU") != "sse3=off" {
t.Skipf("skipping test: GODEBUGCPU=sse3=off not set")
}
want := false
if got := X86.HasSSE3; got != want {
t.Errorf("X86.HasSSE3 expected %v, got %v", want, got)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment