Source file src/internal/cpu/cpu.go

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package cpu implements processor feature detection
     6  // used by the Go standard library.
     7  package cpu
     8  
     9  // DebugOptions is set to true by the runtime if the OS supports reading
    10  // GODEBUG early in runtime startup.
    11  // This should not be changed after it is initialized.
    12  var DebugOptions bool
    13  
    14  // CacheLinePad is used to pad structs to avoid false sharing.
    15  type CacheLinePad struct{ _ [CacheLinePadSize]byte }
    16  
    17  // CacheLineSize is the CPU's assumed cache line size.
    18  // There is currently no runtime detection of the real cache line size
    19  // so we use the constant per GOARCH CacheLinePadSize as an approximation.
    20  var CacheLineSize uintptr = CacheLinePadSize
    21  
    22  // The booleans in X86 contain the correspondingly named cpuid feature bit.
    23  // HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers
    24  // in addition to the cpuid feature bit being set.
    25  // The struct is padded to avoid false sharing.
    26  var X86 struct {
    27  	_            CacheLinePad
    28  	HasAES       bool
    29  	HasADX       bool
    30  	HasAVX       bool
    31  	HasAVX2      bool
    32  	HasAVX512F   bool
    33  	HasAVX512BW  bool
    34  	HasAVX512VL  bool
    35  	HasBMI1      bool
    36  	HasBMI2      bool
    37  	HasERMS      bool
    38  	HasFMA       bool
    39  	HasOSXSAVE   bool
    40  	HasPCLMULQDQ bool
    41  	HasPOPCNT    bool
    42  	HasRDTSCP    bool
    43  	HasSHA       bool
    44  	HasSSE3      bool
    45  	HasSSSE3     bool
    46  	HasSSE41     bool
    47  	HasSSE42     bool
    48  	_            CacheLinePad
    49  }
    50  
    51  // The booleans in ARM contain the correspondingly named cpu feature bit.
    52  // The struct is padded to avoid false sharing.
    53  var ARM struct {
    54  	_            CacheLinePad
    55  	HasVFPv4     bool
    56  	HasIDIVA     bool
    57  	HasV7Atomics bool
    58  	_            CacheLinePad
    59  }
    60  
    61  // The booleans in ARM64 contain the correspondingly named cpu feature bit.
    62  // The struct is padded to avoid false sharing.
    63  var ARM64 struct {
    64  	_          CacheLinePad
    65  	HasAES     bool
    66  	HasPMULL   bool
    67  	HasSHA1    bool
    68  	HasSHA2    bool
    69  	HasSHA512  bool
    70  	HasCRC32   bool
    71  	HasATOMICS bool
    72  	HasCPUID   bool
    73  	IsNeoverse bool
    74  	_          CacheLinePad
    75  }
    76  
    77  var MIPS64X struct {
    78  	_      CacheLinePad
    79  	HasMSA bool // MIPS SIMD architecture
    80  	_      CacheLinePad
    81  }
    82  
    83  // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00,
    84  // since there are no optional categories. There are some exceptions that also
    85  // require kernel support to work (darn, scv), so there are feature bits for
    86  // those as well. The minimum processor requirement is POWER8 (ISA 2.07).
    87  // The struct is padded to avoid false sharing.
    88  var PPC64 struct {
    89  	_         CacheLinePad
    90  	HasDARN   bool // Hardware random number generator (requires kernel enablement)
    91  	HasSCV    bool // Syscall vectored (requires kernel enablement)
    92  	IsPOWER8  bool // ISA v2.07 (POWER8)
    93  	IsPOWER9  bool // ISA v3.00 (POWER9)
    94  	IsPOWER10 bool // ISA v3.1  (POWER10)
    95  	_         CacheLinePad
    96  }
    97  
    98  var S390X struct {
    99  	_         CacheLinePad
   100  	HasZARCH  bool // z architecture mode is active [mandatory]
   101  	HasSTFLE  bool // store facility list extended [mandatory]
   102  	HasLDISP  bool // long (20-bit) displacements [mandatory]
   103  	HasEIMM   bool // 32-bit immediates [mandatory]
   104  	HasDFP    bool // decimal floating point
   105  	HasETF3EH bool // ETF-3 enhanced
   106  	HasMSA    bool // message security assist (CPACF)
   107  	HasAES    bool // KM-AES{128,192,256} functions
   108  	HasAESCBC bool // KMC-AES{128,192,256} functions
   109  	HasAESCTR bool // KMCTR-AES{128,192,256} functions
   110  	HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
   111  	HasGHASH  bool // KIMD-GHASH function
   112  	HasSHA1   bool // K{I,L}MD-SHA-1 functions
   113  	HasSHA256 bool // K{I,L}MD-SHA-256 functions
   114  	HasSHA512 bool // K{I,L}MD-SHA-512 functions
   115  	HasSHA3   bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
   116  	HasVX     bool // vector facility. Note: the runtime sets this when it processes auxv records.
   117  	HasVXE    bool // vector-enhancements facility 1
   118  	HasKDSA   bool // elliptic curve functions
   119  	HasECDSA  bool // NIST curves
   120  	HasEDDSA  bool // Edwards curves
   121  	_         CacheLinePad
   122  }
   123  
   124  // Initialize examines the processor and sets the relevant variables above.
   125  // This is called by the runtime package early in program initialization,
   126  // before normal init functions are run. env is set by runtime if the OS supports
   127  // cpu feature options in GODEBUG.
   128  func Initialize(env string) {
   129  	doinit()
   130  	processOptions(env)
   131  }
   132  
   133  // options contains the cpu debug options that can be used in GODEBUG.
   134  // Options are arch dependent and are added by the arch specific doinit functions.
   135  // Features that are mandatory for the specific GOARCH should not be added to options
   136  // (e.g. SSE2 on amd64).
   137  var options []option
   138  
   139  // Option names should be lower case. e.g. avx instead of AVX.
   140  type option struct {
   141  	Name      string
   142  	Feature   *bool
   143  	Specified bool // whether feature value was specified in GODEBUG
   144  	Enable    bool // whether feature should be enabled
   145  }
   146  
   147  // processOptions enables or disables CPU feature values based on the parsed env string.
   148  // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2...
   149  // where feature names is one of the architecture specific list stored in the
   150  // cpu packages options variable and values are either 'on' or 'off'.
   151  // If env contains cpu.all=off then all cpu features referenced through the options
   152  // variable are disabled. Other feature names and values result in warning messages.
   153  func processOptions(env string) {
   154  field:
   155  	for env != "" {
   156  		field := ""
   157  		i := indexByte(env, ',')
   158  		if i < 0 {
   159  			field, env = env, ""
   160  		} else {
   161  			field, env = env[:i], env[i+1:]
   162  		}
   163  		if len(field) < 4 || field[:4] != "cpu." {
   164  			continue
   165  		}
   166  		i = indexByte(field, '=')
   167  		if i < 0 {
   168  			print("GODEBUG: no value specified for \"", field, "\"\n")
   169  			continue
   170  		}
   171  		key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
   172  
   173  		var enable bool
   174  		switch value {
   175  		case "on":
   176  			enable = true
   177  		case "off":
   178  			enable = false
   179  		default:
   180  			print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
   181  			continue field
   182  		}
   183  
   184  		if key == "all" {
   185  			for i := range options {
   186  				options[i].Specified = true
   187  				options[i].Enable = enable
   188  			}
   189  			continue field
   190  		}
   191  
   192  		for i := range options {
   193  			if options[i].Name == key {
   194  				options[i].Specified = true
   195  				options[i].Enable = enable
   196  				continue field
   197  			}
   198  		}
   199  
   200  		print("GODEBUG: unknown cpu feature \"", key, "\"\n")
   201  	}
   202  
   203  	for _, o := range options {
   204  		if !o.Specified {
   205  			continue
   206  		}
   207  
   208  		if o.Enable && !*o.Feature {
   209  			print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n")
   210  			continue
   211  		}
   212  
   213  		*o.Feature = o.Enable
   214  	}
   215  }
   216  
   217  // indexByte returns the index of the first instance of c in s,
   218  // or -1 if c is not present in s.
   219  // indexByte is semantically the same as [strings.IndexByte].
   220  // We copy this function because "internal/cpu" should not have external dependencies.
   221  func indexByte(s string, c byte) int {
   222  	for i := 0; i < len(s); i++ {
   223  		if s[i] == c {
   224  			return i
   225  		}
   226  	}
   227  	return -1
   228  }
   229  

View as plain text