From b7a2d413a3f710f14accedf185c93bfb63d24fd0 Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Tue, 20 Oct 2020 09:56:14 +0200 Subject: testing: print cpu type as label for benchmarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supports 386 and amd64 architectures on all operating systems. Example output: $ go test -bench=.* goos: darwin goarch: amd64 pkg: strconv cpu: Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz BenchmarkAtof64Decimal-4 24431032 46.8 ns/op ... As the displayed CPU information is only used for information purposes it is lazily initialized when needed using the new internal/sysinfo package. This allows internal/cpu to stay without dependencies and avoid initialization costs when the CPU information is not needed as the new code to query the CPU name in internal/cpu can be dead code eliminated if not used. Fixes #39214 Change-Id: I77ae5c5d2fed6b28fa78dd45075f9f0a6a7f1bfd Reviewed-on: https://go-review.googlesource.com/c/go/+/263804 Trust: Martin Möhrmann Reviewed-by: Keith Randall --- src/internal/cpu/cpu_x86.go | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src/internal/cpu/cpu_x86.go') diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go index da6cf67258..fb414adaf8 100644 --- a/src/internal/cpu/cpu_x86.go +++ b/src/internal/cpu/cpu_x86.go @@ -38,6 +38,8 @@ const ( cpuid_ADX = 1 << 19 ) +var maxExtendedFunctionInformation uint32 + func doinit() { options = []option{ {Name: "adx", Feature: &X86.HasADX}, @@ -65,6 +67,8 @@ func doinit() { return } + maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0) + _, _, ecx1, edx1 := cpuid(1, 0) X86.HasSSE2 = isSet(edx1, cpuid_SSE2) @@ -103,3 +107,48 @@ func doinit() { func isSet(hwc uint32, value uint32) bool { return hwc&value != 0 } + +// Name returns the CPU name given by the vendor. +// If the CPU name can not be determined an +// empty string is returned. +func Name() string { + if maxExtendedFunctionInformation < 0x80000004 { + return "" + } + + data := make([]byte, 0, 3*4*4) + + var eax, ebx, ecx, edx uint32 + eax, ebx, ecx, edx = cpuid(0x80000002, 0) + data = appendBytes(data, eax, ebx, ecx, edx) + eax, ebx, ecx, edx = cpuid(0x80000003, 0) + data = appendBytes(data, eax, ebx, ecx, edx) + eax, ebx, ecx, edx = cpuid(0x80000004, 0) + data = appendBytes(data, eax, ebx, ecx, edx) + + // Trim leading spaces. + for len(data) > 0 && data[0] == ' ' { + data = data[1:] + } + + // Trim tail after and including the first null byte. + for i, c := range data { + if c == '\x00' { + data = data[:i] + break + } + } + + return string(data) +} + +func appendBytes(b []byte, args ...uint32) []byte { + for _, arg := range args { + b = append(b, + byte((arg >> 0)), + byte((arg >> 8)), + byte((arg >> 16)), + byte((arg >> 24))) + } + return b +} -- cgit v1.3 From dda2991c2ea0c5914714469c4defc2562a907230 Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Thu, 3 Dec 2020 16:41:57 +0100 Subject: internal/cpu: disable FMA when OSXSAVE is not enabled on x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All instructions in the FMA extension on x86 are VEX prefixed. VEX prefixed instructions generally require OSXSAVE to be enabled. The execution of FMA instructions emitted by the Go compiler on amd64 will generate an invalid opcode exception if OSXSAVE is not enabled. Fixes #41022 Change-Id: I49881630e7195c804110a2bd81b5bec8cac31ba8 Reviewed-on: https://go-review.googlesource.com/c/go/+/274479 Trust: Martin Möhrmann Run-TryBot: Martin Möhrmann TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/internal/cpu/cpu_x86.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/internal/cpu/cpu_x86.go') diff --git a/src/internal/cpu/cpu_x86.go b/src/internal/cpu/cpu_x86.go index fb414adaf8..ba6bf69034 100644 --- a/src/internal/cpu/cpu_x86.go +++ b/src/internal/cpu/cpu_x86.go @@ -75,13 +75,22 @@ func doinit() { X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) - X86.HasFMA = isSet(ecx1, cpuid_FMA) X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) X86.HasAES = isSet(ecx1, cpuid_AES) + + // OSXSAVE can be false when using older Operating Systems + // or when explicitly disabled on newer Operating Systems by + // e.g. setting the xsavedisable boot option on Windows 10. X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) + // The FMA instruction set extension only has VEX prefixed instructions. + // VEX prefixed instructions require OSXSAVE to be enabled. + // See Intel 64 and IA-32 Architecture Software Developer’s Manual Volume 2 + // Section 2.4 "AVX and SSE Instruction Exception Specification" + X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE + osSupportsAVX := false // For XGETBV, OSXSAVE bit is required and sufficient. if X86.HasOSXSAVE { -- cgit v1.3