Codebase list golang-github-klauspost-cpuid / upstream/0.0_git20151214.0.ef30b90
Imported Upstream version 0.0~git20151214.0.ef30b90 Alexandre Viau 8 years ago
21 changed file(s) with 4600 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 language: go
1
2 go:
3 - 1.3
4 - 1.4
5 - 1.5
6 - tip
0 The MIT License (MIT)
1
2 Copyright (c) 2015 Klaus Post
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21
0 # cpuid
1 Package cpuid provides information about the CPU running the current program.
2
3 CPU features are detected on startup, and kept for fast access through the life of the application.
4 Currently x86 / x64 (AMD64) is supported, and no external C (cgo) code is used, which should make the library very easy to use.
5
6 You can access the CPU information by accessing the shared CPU variable of the cpuid library.
7
8 Package home: https://github.com/klauspost/cpuid
9
10 [![GoDoc][1]][2] [![Build Status][3]][4]
11
12 [1]: https://godoc.org/github.com/klauspost/cpuid?status.svg
13 [2]: https://godoc.org/github.com/klauspost/cpuid
14 [3]: https://travis-ci.org/klauspost/cpuid.svg
15 [4]: https://travis-ci.org/klauspost/cpuid
16
17 # features
18 ## CPU Instructions
19 * **CMOV** (i686 CMOV)
20 * **NX** (NX (No-Execute) bit)
21 * **AMD3DNOW** (AMD 3DNOW)
22 * **AMD3DNOWEXT** (AMD 3DNowExt)
23 * **MMX** (standard MMX)
24 * **MMXEXT** (SSE integer functions or AMD MMX ext)
25 * **SSE** (SSE functions)
26 * **SSE2** (P4 SSE functions)
27 * **SSE3** (Prescott SSE3 functions)
28 * **SSSE3** (Conroe SSSE3 functions)
29 * **SSE4** (Penryn SSE4.1 functions)
30 * **SSE4A** (AMD Barcelona microarchitecture SSE4a instructions)
31 * **SSE42** (Nehalem SSE4.2 functions)
32 * **AVX** (AVX functions)
33 * **AVX2** (AVX2 functions)
34 * **FMA3** (Intel FMA 3)
35 * **FMA4** (Bulldozer FMA4 functions)
36 * **XOP** (Bulldozer XOP functions)
37 * **F16C** (Half-precision floating-point conversion)
38 * **BMI1** (Bit Manipulation Instruction Set 1)
39 * **BMI2** (Bit Manipulation Instruction Set 2)
40 * **TBM** (AMD Trailing Bit Manipulation)
41 * **LZCNT** (LZCNT instruction)
42 * **POPCNT** (POPCNT instruction)
43 * **AESNI** (Advanced Encryption Standard New Instructions)
44 * **CLMUL** (Carry-less Multiplication)
45 * **HTT** (Hyperthreading (enabled))
46 * **HLE** (Hardware Lock Elision)
47 * **RTM** (Restricted Transactional Memory)
48 * **RDRAND** (RDRAND instruction is available)
49 * **RDSEED** (RDSEED instruction is available)
50 * **ADX** (Intel ADX (Multi-Precision Add-Carry Instruction Extensions))
51 * **SHA** (Intel SHA Extensions)
52 * **AVX512F** (AVX-512 Foundation)
53 * **AVX512DQ** (AVX-512 Doubleword and Quadword Instructions)
54 * **AVX512IFMA** (AVX-512 Integer Fused Multiply-Add Instructions)
55 * **AVX512PF** (AVX-512 Prefetch Instructions)
56 * **AVX512ER** (AVX-512 Exponential and Reciprocal Instructions)
57 * **AVX512CD** (AVX-512 Conflict Detection Instructions)
58 * **AVX512BW** (AVX-512 Byte and Word Instructions)
59 * **AVX512VL** (AVX-512 Vector Length Extensions)
60 * **AVX512VBMI** (AVX-512 Vector Bit Manipulation Instructions)
61 * **MPX** (Intel MPX (Memory Protection Extensions))
62 * **ERMS** (Enhanced REP MOVSB/STOSB)
63 * **RDTSCP** (RDTSCP Instruction)
64 * **CX16** (CMPXCHG16B Instruction)
65
66 ## Performance
67 * **RDTSCP()** Returns current cycle count. Can be used for benchmarking.
68 * **SSE2SLOW** (SSE2 is supported, but usually not faster)
69 * **SSE3SLOW** (SSE3 is supported, but usually not faster)
70 * **ATOM** (Atom processor, some SSSE3 instructions are slower)
71 * **Cache line** (Probable size of a cache line).
72 * **L1, L2, L3 Cache size** on newer Intel/AMD CPUs.
73
74 ## Cpu Vendor/VM
75 * **Intel**
76 * **AMD**
77 * **VIA**
78 * **Transmeta**
79 * **NSC**
80 * **KVM** (Kernel-based Virtual Machine)
81 * **MSVM** (Microsoft Hyper-V or Windows Virtual PC)
82 * **VMware**
83 * **XenHVM**
84
85 # installing
86
87 ```go get github.com/klauspost/cpuid```
88
89 # example
90
91 ```Go
92 package main
93
94 import (
95 "fmt"
96 "github.com/klauspost/cpuid"
97 )
98
99 func main() {
100 // Print basic CPU information:
101 fmt.Println("Name:", cpuid.CPU.BrandName)
102 fmt.Println("PhysicalCores:", cpuid.CPU.PhysicalCores)
103 fmt.Println("ThreadsPerCore:", cpuid.CPU.ThreadsPerCore)
104 fmt.Println("LogicalCores:", cpuid.CPU.LogicalCores)
105 fmt.Println("Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model)
106 fmt.Println("Features:", cpuid.CPU.Features)
107 fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine)
108 fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes")
109 fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1D, "bytes")
110 fmt.Println("L2 Cache:", cpuid.CPU.Cache.L2, "bytes")
111 fmt.Println("L3 Cache:", cpuid.CPU.Cache.L3, "bytes")
112
113 // Test if we have a specific feature:
114 if cpuid.CPU.SSE() {
115 fmt.Println("We have Streaming SIMD Extensions")
116 }
117 }
118 ```
119
120 Sample output:
121 ```
122 >go run main.go
123 Name: Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz
124 PhysicalCores: 2
125 ThreadsPerCore: 2
126 LogicalCores: 4
127 Family 6 Model: 42
128 Features: CMOV,MMX,MMXEXT,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2,AVX,AESNI,CLMUL
129 Cacheline bytes: 64
130 We have Streaming SIMD Extensions
131 ```
132
133 # private package
134
135 In the "private" folder you can find an autogenerated version of the library you can include in your own packages.
136
137 For this purpose all exports are removed, and functions and constants are lowercased.
138
139 This is not a recommended way of using the library, but provided for convenience, if it is difficult for you to use external packages.
140
141 # license
142
143 This code is published under an MIT license. See LICENSE file for more information.
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // Package cpuid provides information about the CPU running the current program.
3 //
4 // CPU features are detected on startup, and kept for fast access through the life of the application.
5 // Currently x86 / x64 (AMD64) is supported.
6 //
7 // You can access the CPU information by accessing the shared CPU variable of the cpuid library.
8 //
9 // Package home: https://github.com/klauspost/cpuid
10 package cpuid
11
12 import (
13 "strings"
14 )
15
16 // Vendor is a representation of a CPU vendor.
17 type Vendor int
18
19 const (
20 Other Vendor = iota
21 Intel
22 AMD
23 VIA
24 Transmeta
25 NSC
26 KVM // Kernel-based Virtual Machine
27 MSVM // Microsoft Hyper-V or Windows Virtual PC
28 VMware
29 XenHVM
30 )
31
32 const (
33 CMOV = 1 << iota // i686 CMOV
34 NX // NX (No-Execute) bit
35 AMD3DNOW // AMD 3DNOW
36 AMD3DNOWEXT // AMD 3DNowExt
37 MMX // standard MMX
38 MMXEXT // SSE integer functions or AMD MMX ext
39 SSE // SSE functions
40 SSE2 // P4 SSE functions
41 SSE3 // Prescott SSE3 functions
42 SSSE3 // Conroe SSSE3 functions
43 SSE4 // Penryn SSE4.1 functions
44 SSE4A // AMD Barcelona microarchitecture SSE4a instructions
45 SSE42 // Nehalem SSE4.2 functions
46 AVX // AVX functions
47 AVX2 // AVX2 functions
48 FMA3 // Intel FMA 3
49 FMA4 // Bulldozer FMA4 functions
50 XOP // Bulldozer XOP functions
51 F16C // Half-precision floating-point conversion
52 BMI1 // Bit Manipulation Instruction Set 1
53 BMI2 // Bit Manipulation Instruction Set 2
54 TBM // AMD Trailing Bit Manipulation
55 LZCNT // LZCNT instruction
56 POPCNT // POPCNT instruction
57 AESNI // Advanced Encryption Standard New Instructions
58 CLMUL // Carry-less Multiplication
59 HTT // Hyperthreading (enabled)
60 HLE // Hardware Lock Elision
61 RTM // Restricted Transactional Memory
62 RDRAND // RDRAND instruction is available
63 RDSEED // RDSEED instruction is available
64 ADX // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
65 SHA // Intel SHA Extensions
66 AVX512F // AVX-512 Foundation
67 AVX512DQ // AVX-512 Doubleword and Quadword Instructions
68 AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions
69 AVX512PF // AVX-512 Prefetch Instructions
70 AVX512ER // AVX-512 Exponential and Reciprocal Instructions
71 AVX512CD // AVX-512 Conflict Detection Instructions
72 AVX512BW // AVX-512 Byte and Word Instructions
73 AVX512VL // AVX-512 Vector Length Extensions
74 AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions
75 MPX // Intel MPX (Memory Protection Extensions)
76 ERMS // Enhanced REP MOVSB/STOSB
77 RDTSCP // RDTSCP Instruction
78 CX16 // CMPXCHG16B Instruction
79
80 // Performance indicators
81 SSE2SLOW // SSE2 is supported, but usually not faster
82 SSE3SLOW // SSE3 is supported, but usually not faster
83 ATOM // Atom processor, some SSSE3 instructions are slower
84 )
85
86 var flagNames = map[Flags]string{
87 CMOV: "CMOV", // i686 CMOV
88 NX: "NX", // NX (No-Execute) bit
89 AMD3DNOW: "AMD3DNOW", // AMD 3DNOW
90 AMD3DNOWEXT: "AMD3DNOWEXT", // AMD 3DNowExt
91 MMX: "MMX", // Standard MMX
92 MMXEXT: "MMXEXT", // SSE integer functions or AMD MMX ext
93 SSE: "SSE", // SSE functions
94 SSE2: "SSE2", // P4 SSE2 functions
95 SSE3: "SSE3", // Prescott SSE3 functions
96 SSSE3: "SSSE3", // Conroe SSSE3 functions
97 SSE4: "SSE4.1", // Penryn SSE4.1 functions
98 SSE4A: "SSE4A", // AMD Barcelona microarchitecture SSE4a instructions
99 SSE42: "SSE4.2", // Nehalem SSE4.2 functions
100 AVX: "AVX", // AVX functions
101 AVX2: "AVX2", // AVX functions
102 FMA3: "FMA3", // Intel FMA 3
103 FMA4: "FMA4", // Bulldozer FMA4 functions
104 XOP: "XOP", // Bulldozer XOP functions
105 F16C: "F16C", // Half-precision floating-point conversion
106 BMI1: "BMI1", // Bit Manipulation Instruction Set 1
107 BMI2: "BMI2", // Bit Manipulation Instruction Set 2
108 TBM: "TBM", // AMD Trailing Bit Manipulation
109 LZCNT: "LZCNT", // LZCNT instruction
110 POPCNT: "POPCNT", // POPCNT instruction
111 AESNI: "AESNI", // Advanced Encryption Standard New Instructions
112 CLMUL: "CLMUL", // Carry-less Multiplication
113 HTT: "HTT", // Hyperthreading (enabled)
114 HLE: "HLE", // Hardware Lock Elision
115 RTM: "RTM", // Restricted Transactional Memory
116 RDRAND: "RDRAND", // RDRAND instruction is available
117 RDSEED: "RDSEED", // RDSEED instruction is available
118 ADX: "ADX", // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
119 SHA: "SHA", // Intel SHA Extensions
120 AVX512F: "AVX512F", // AVX-512 Foundation
121 AVX512DQ: "AVX512DQ", // AVX-512 Doubleword and Quadword Instructions
122 AVX512IFMA: "AVX512IFMA", // AVX-512 Integer Fused Multiply-Add Instructions
123 AVX512PF: "AVX512PF", // AVX-512 Prefetch Instructions
124 AVX512ER: "AVX512ER", // AVX-512 Exponential and Reciprocal Instructions
125 AVX512CD: "AVX512CD", // AVX-512 Conflict Detection Instructions
126 AVX512BW: "AVX512BW", // AVX-512 Byte and Word Instructions
127 AVX512VL: "AVX512VL", // AVX-512 Vector Length Extensions
128 AVX512VBMI: "AVX512VBMI", // AVX-512 Vector Bit Manipulation Instructions
129 MPX: "MPX", // Intel MPX (Memory Protection Extensions)
130 ERMS: "ERMS", // Enhanced REP MOVSB/STOSB
131 RDTSCP: "RDTSCP", // RDTSCP Instruction
132 CX16: "CX16", // CMPXCHG16B Instruction
133
134 // Performance indicators
135 SSE2SLOW: "SSE2SLOW", // SSE2 supported, but usually not faster
136 SSE3SLOW: "SSE3SLOW", // SSE3 supported, but usually not faster
137 ATOM: "ATOM", // Atom processor, some SSSE3 instructions are slower
138
139 }
140
141 // CPUInfo contains information about the detected system CPU.
142 type CPUInfo struct {
143 BrandName string // Brand name reported by the CPU
144 VendorID Vendor // Comparable CPU vendor ID
145 Features Flags // Features of the CPU
146 PhysicalCores int // Number of physical processor cores in your CPU. Will be 0 if undetectable.
147 ThreadsPerCore int // Number of threads per physical core. Will be 1 if undetectable.
148 LogicalCores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable.
149 Family int // CPU family number
150 Model int // CPU model number
151 CacheLine int // Cache line size in bytes. Will be 0 if undetectable.
152 Cache struct {
153 L1I int // L1 Instruction Cache (per core or shared). Will be -1 if undetected
154 L1D int // L1 Data Cache (per core or shared). Will be -1 if undetected
155 L2 int // L2 Cache (per core or shared). Will be -1 if undetected
156 L3 int // L3 Instruction Cache (per core or shared). Will be -1 if undetected
157 }
158 maxFunc uint32
159 maxExFunc uint32
160 }
161
162 var cpuid func(op uint32) (eax, ebx, ecx, edx uint32)
163 var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32)
164 var xgetbv func(index uint32) (eax, edx uint32)
165 var rdtscpAsm func() (eax, ebx, ecx, edx uint32)
166
167 // CPU contains information about the CPU as detected on startup,
168 // or when Detect last was called.
169 //
170 // Use this as the primary entry point to you data,
171 // this way queries are
172 var CPU CPUInfo
173
174 func init() {
175 initCPU()
176 Detect()
177 }
178
179 // Detect will re-detect current CPU info.
180 // This will replace the content of the exported CPU variable.
181 //
182 // Unless you expect the CPU to change while you are running your program
183 // you should not need to call this function.
184 // If you call this, you must ensure that no other goroutine is accessing the
185 // exported CPU variable.
186 func Detect() {
187 CPU.maxFunc = maxFunctionID()
188 CPU.maxExFunc = maxExtendedFunction()
189 CPU.BrandName = brandName()
190 CPU.CacheLine = cacheLine()
191 CPU.Family, CPU.Model = familyModel()
192 CPU.Features = support()
193 CPU.ThreadsPerCore = threadsPerCore()
194 CPU.LogicalCores = logicalCores()
195 CPU.PhysicalCores = physicalCores()
196 CPU.VendorID = vendorID()
197 CPU.cacheSize()
198 }
199
200 // Generated here: http://play.golang.org/p/BxFH2Gdc0G
201
202 // Cmov indicates support of CMOV instructions
203 func (c CPUInfo) Cmov() bool {
204 return c.Features&CMOV != 0
205 }
206
207 // Amd3dnow indicates support of AMD 3DNOW! instructions
208 func (c CPUInfo) Amd3dnow() bool {
209 return c.Features&AMD3DNOW != 0
210 }
211
212 // Amd3dnowExt indicates support of AMD 3DNOW! Extended instructions
213 func (c CPUInfo) Amd3dnowExt() bool {
214 return c.Features&AMD3DNOWEXT != 0
215 }
216
217 // MMX indicates support of MMX instructions
218 func (c CPUInfo) MMX() bool {
219 return c.Features&MMX != 0
220 }
221
222 // MMXExt indicates support of MMXEXT instructions
223 // (SSE integer functions or AMD MMX ext)
224 func (c CPUInfo) MMXExt() bool {
225 return c.Features&MMXEXT != 0
226 }
227
228 // SSE indicates support of SSE instructions
229 func (c CPUInfo) SSE() bool {
230 return c.Features&SSE != 0
231 }
232
233 // SSE2 indicates support of SSE 2 instructions
234 func (c CPUInfo) SSE2() bool {
235 return c.Features&SSE2 != 0
236 }
237
238 // SSE3 indicates support of SSE 3 instructions
239 func (c CPUInfo) SSE3() bool {
240 return c.Features&SSE3 != 0
241 }
242
243 // SSSE3 indicates support of SSSE 3 instructions
244 func (c CPUInfo) SSSE3() bool {
245 return c.Features&SSSE3 != 0
246 }
247
248 // SSE4 indicates support of SSE 4 (also called SSE 4.1) instructions
249 func (c CPUInfo) SSE4() bool {
250 return c.Features&SSE4 != 0
251 }
252
253 // SSE42 indicates support of SSE4.2 instructions
254 func (c CPUInfo) SSE42() bool {
255 return c.Features&SSE42 != 0
256 }
257
258 // AVX indicates support of AVX instructions
259 // and operating system support of AVX instructions
260 func (c CPUInfo) AVX() bool {
261 return c.Features&AVX != 0
262 }
263
264 // AVX2 indicates support of AVX2 instructions
265 func (c CPUInfo) AVX2() bool {
266 return c.Features&AVX2 != 0
267 }
268
269 // FMA3 indicates support of FMA3 instructions
270 func (c CPUInfo) FMA3() bool {
271 return c.Features&FMA3 != 0
272 }
273
274 // FMA4 indicates support of FMA4 instructions
275 func (c CPUInfo) FMA4() bool {
276 return c.Features&FMA4 != 0
277 }
278
279 // XOP indicates support of XOP instructions
280 func (c CPUInfo) XOP() bool {
281 return c.Features&XOP != 0
282 }
283
284 // F16C indicates support of F16C instructions
285 func (c CPUInfo) F16C() bool {
286 return c.Features&F16C != 0
287 }
288
289 // BMI1 indicates support of BMI1 instructions
290 func (c CPUInfo) BMI1() bool {
291 return c.Features&BMI1 != 0
292 }
293
294 // BMI2 indicates support of BMI2 instructions
295 func (c CPUInfo) BMI2() bool {
296 return c.Features&BMI2 != 0
297 }
298
299 // TBM indicates support of TBM instructions
300 // (AMD Trailing Bit Manipulation)
301 func (c CPUInfo) TBM() bool {
302 return c.Features&TBM != 0
303 }
304
305 // Lzcnt indicates support of LZCNT instruction
306 func (c CPUInfo) Lzcnt() bool {
307 return c.Features&LZCNT != 0
308 }
309
310 // Popcnt indicates support of POPCNT instruction
311 func (c CPUInfo) Popcnt() bool {
312 return c.Features&POPCNT != 0
313 }
314
315 // HTT indicates the processor has Hyperthreading enabled
316 func (c CPUInfo) HTT() bool {
317 return c.Features&HTT != 0
318 }
319
320 // SSE2Slow indicates that SSE2 may be slow on this processor
321 func (c CPUInfo) SSE2Slow() bool {
322 return c.Features&SSE2SLOW != 0
323 }
324
325 // SSE3Slow indicates that SSE3 may be slow on this processor
326 func (c CPUInfo) SSE3Slow() bool {
327 return c.Features&SSE3SLOW != 0
328 }
329
330 // AesNi indicates support of AES-NI instructions
331 // (Advanced Encryption Standard New Instructions)
332 func (c CPUInfo) AesNi() bool {
333 return c.Features&AESNI != 0
334 }
335
336 // Clmul indicates support of CLMUL instructions
337 // (Carry-less Multiplication)
338 func (c CPUInfo) Clmul() bool {
339 return c.Features&CLMUL != 0
340 }
341
342 // NX indicates support of NX (No-Execute) bit
343 func (c CPUInfo) NX() bool {
344 return c.Features&NX != 0
345 }
346
347 // SSE4A indicates support of AMD Barcelona microarchitecture SSE4a instructions
348 func (c CPUInfo) SSE4A() bool {
349 return c.Features&SSE4A != 0
350 }
351
352 // HLE indicates support of Hardware Lock Elision
353 func (c CPUInfo) HLE() bool {
354 return c.Features&HLE != 0
355 }
356
357 // RTM indicates support of Restricted Transactional Memory
358 func (c CPUInfo) RTM() bool {
359 return c.Features&RTM != 0
360 }
361
362 // Rdrand indicates support of RDRAND instruction is available
363 func (c CPUInfo) Rdrand() bool {
364 return c.Features&RDRAND != 0
365 }
366
367 // Rdseed indicates support of RDSEED instruction is available
368 func (c CPUInfo) Rdseed() bool {
369 return c.Features&RDSEED != 0
370 }
371
372 // ADX indicates support of Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
373 func (c CPUInfo) ADX() bool {
374 return c.Features&ADX != 0
375 }
376
377 // SHA indicates support of Intel SHA Extensions
378 func (c CPUInfo) SHA() bool {
379 return c.Features&SHA != 0
380 }
381
382 // AVX512F indicates support of AVX-512 Foundation
383 func (c CPUInfo) AVX512F() bool {
384 return c.Features&AVX512F != 0
385 }
386
387 // AVX512DQ indicates support of AVX-512 Doubleword and Quadword Instructions
388 func (c CPUInfo) AVX512DQ() bool {
389 return c.Features&AVX512DQ != 0
390 }
391
392 // AVX512IFMA indicates support of AVX-512 Integer Fused Multiply-Add Instructions
393 func (c CPUInfo) AVX512IFMA() bool {
394 return c.Features&AVX512IFMA != 0
395 }
396
397 // AVX512PF indicates support of AVX-512 Prefetch Instructions
398 func (c CPUInfo) AVX512PF() bool {
399 return c.Features&AVX512PF != 0
400 }
401
402 // AVX512ER indicates support of AVX-512 Exponential and Reciprocal Instructions
403 func (c CPUInfo) AVX512ER() bool {
404 return c.Features&AVX512ER != 0
405 }
406
407 // AVX512CD indicates support of AVX-512 Conflict Detection Instructions
408 func (c CPUInfo) AVX512CD() bool {
409 return c.Features&AVX512CD != 0
410 }
411
412 // AVX512BW indicates support of AVX-512 Byte and Word Instructions
413 func (c CPUInfo) AVX512BW() bool {
414 return c.Features&AVX512BW != 0
415 }
416
417 // AVX512VL indicates support of AVX-512 Vector Length Extensions
418 func (c CPUInfo) AVX512VL() bool {
419 return c.Features&AVX512VL != 0
420 }
421
422 // AVX512VBMI indicates support of AVX-512 Vector Bit Manipulation Instructions
423 func (c CPUInfo) AVX512VBMI() bool {
424 return c.Features&AVX512VBMI != 0
425 }
426
427 // MPX indicates support of Intel MPX (Memory Protection Extensions)
428 func (c CPUInfo) MPX() bool {
429 return c.Features&MPX != 0
430 }
431
432 // ERMS indicates support of Enhanced REP MOVSB/STOSB
433 func (c CPUInfo) ERMS() bool {
434 return c.Features&ERMS != 0
435 }
436
437 func (c CPUInfo) RDTSCP() bool {
438 return c.Features&RDTSCP != 0
439 }
440
441 func (c CPUInfo) CX16() bool {
442 return c.Features&CX16 != 0
443 }
444
445 // Atom indicates an Atom processor
446 func (c CPUInfo) Atom() bool {
447 return c.Features&ATOM != 0
448 }
449
450 // Intel returns true if vendor is recognized as Intel
451 func (c CPUInfo) Intel() bool {
452 return c.VendorID == Intel
453 }
454
455 // AMD returns true if vendor is recognized as AMD
456 func (c CPUInfo) AMD() bool {
457 return c.VendorID == AMD
458 }
459
460 // Transmeta returns true if vendor is recognized as Transmeta
461 func (c CPUInfo) Transmeta() bool {
462 return c.VendorID == Transmeta
463 }
464
465 // NSC returns true if vendor is recognized as National Semiconductor
466 func (c CPUInfo) NSC() bool {
467 return c.VendorID == NSC
468 }
469
470 // VIA returns true if vendor is recognized as VIA
471 func (c CPUInfo) VIA() bool {
472 return c.VendorID == VIA
473 }
474
475 // RTCounter returns the 64-bit time-stamp counter
476 // Uses the RDTSCP instruction. The value 0 is returned
477 // if the CPU does not support the instruction.
478 func (c CPUInfo) RTCounter() uint64 {
479 if !c.RDTSCP() {
480 return 0
481 }
482 a, _, _, d := rdtscpAsm()
483 return uint64(a) | (uint64(d) << 32)
484 }
485
486 // Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP.
487 // This variable is OS dependent, but on Linux contains information
488 // about the current cpu/core the code is running on.
489 // If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned.
490 func (c CPUInfo) Ia32TscAux() uint32 {
491 if !c.RDTSCP() {
492 return 0
493 }
494 _, _, ecx, _ := rdtscpAsm()
495 return ecx
496 }
497
498 // LogicalCPU will return the Logical CPU the code is currently executing on.
499 // This is likely to change when the OS re-schedules the running thread
500 // to another CPU.
501 // If the current core cannot be detected, -1 will be returned.
502 func (c CPUInfo) LogicalCPU() int {
503 if c.maxFunc < 1 {
504 return -1
505 }
506 _, ebx, _, _ := cpuid(1)
507 return int(ebx >> 24)
508 }
509
510 // VM Will return true if the cpu id indicates we are in
511 // a virtual machine. This is only a hint, and will very likely
512 // have many false negatives.
513 func (c CPUInfo) VM() bool {
514 switch c.VendorID {
515 case MSVM, KVM, VMware, XenHVM:
516 return true
517 }
518 return false
519 }
520
521 // Flags contains detected cpu features and caracteristics
522 type Flags uint64
523
524 // String returns a string representation of the detected
525 // CPU features.
526 func (f Flags) String() string {
527 return strings.Join(f.Strings(), ",")
528 }
529
530 // Strings returns and array of the detected features.
531 func (f Flags) Strings() []string {
532 s := support()
533 r := make([]string, 0, 20)
534 for i := uint(0); i < 64; i++ {
535 key := Flags(1 << i)
536 val := flagNames[key]
537 if s&key != 0 {
538 r = append(r, val)
539 }
540 }
541 return r
542 }
543
544 func maxExtendedFunction() uint32 {
545 eax, _, _, _ := cpuid(0x80000000)
546 return eax
547 }
548
549 func maxFunctionID() uint32 {
550 a, _, _, _ := cpuid(0)
551 return a
552 }
553
554 func brandName() string {
555 if maxExtendedFunction() >= 0x80000004 {
556 v := make([]uint32, 0, 48)
557 for i := uint32(0); i < 3; i++ {
558 a, b, c, d := cpuid(0x80000002 + i)
559 v = append(v, a, b, c, d)
560 }
561 return strings.Trim(string(valAsString(v...)), " ")
562 }
563 return "unknown"
564 }
565
566 func threadsPerCore() int {
567 mfi := maxFunctionID()
568 if mfi < 0x4 || vendorID() != Intel {
569 return 1
570 }
571
572 if mfi < 0xb {
573 _, b, _, d := cpuid(1)
574 if (d & (1 << 28)) != 0 {
575 // v will contain logical core count
576 v := (b >> 16) & 255
577 if v > 1 {
578 a4, _, _, _ := cpuid(4)
579 // physical cores
580 v2 := (a4 >> 26) + 1
581 if v2 > 0 {
582 return int(v) / int(v2)
583 }
584 }
585 }
586 return 1
587 }
588 _, b, _, _ := cpuidex(0xb, 0)
589 if b&0xffff == 0 {
590 return 1
591 }
592 return int(b & 0xffff)
593 }
594
595 func logicalCores() int {
596 mfi := maxFunctionID()
597 switch vendorID() {
598 case Intel:
599 // Use this on old Intel processors
600 if mfi < 0xb {
601 if mfi < 1 {
602 return 0
603 }
604 // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID)
605 // that can be assigned to logical processors in a physical package.
606 // The value may not be the same as the number of logical processors that are present in the hardware of a physical package.
607 _, ebx, _, _ := cpuid(1)
608 logical := (ebx >> 16) & 0xff
609 return int(logical)
610 }
611 _, b, _, _ := cpuidex(0xb, 1)
612 return int(b & 0xffff)
613 case AMD:
614 _, b, _, _ := cpuid(1)
615 return int((b >> 16) & 0xff)
616 default:
617 return 0
618 }
619 }
620
621 func familyModel() (int, int) {
622 if maxFunctionID() < 0x1 {
623 return 0, 0
624 }
625 eax, _, _, _ := cpuid(1)
626 family := ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff)
627 model := ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0)
628 return int(family), int(model)
629 }
630
631 func physicalCores() int {
632 switch vendorID() {
633 case Intel:
634 return logicalCores() / threadsPerCore()
635 case AMD:
636 if maxExtendedFunction() >= 0x80000008 {
637 _, _, c, _ := cpuid(0x80000008)
638 return int(c&0xff) + 1
639 }
640 }
641 return 0
642 }
643
644 // Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
645 var vendorMapping = map[string]Vendor{
646 "AMDisbetter!": AMD,
647 "AuthenticAMD": AMD,
648 "CentaurHauls": VIA,
649 "GenuineIntel": Intel,
650 "TransmetaCPU": Transmeta,
651 "GenuineTMx86": Transmeta,
652 "Geode by NSC": NSC,
653 "VIA VIA VIA ": VIA,
654 "KVMKVMKVMKVM": KVM,
655 "Microsoft Hv": MSVM,
656 "VMwareVMware": VMware,
657 "XenVMMXenVMM": XenHVM,
658 }
659
660 func vendorID() Vendor {
661 _, b, c, d := cpuid(0)
662 v := valAsString(b, d, c)
663 vend, ok := vendorMapping[string(v)]
664 if !ok {
665 return Other
666 }
667 return vend
668 }
669
670 func cacheLine() int {
671 if maxFunctionID() < 0x1 {
672 return 0
673 }
674
675 _, ebx, _, _ := cpuid(1)
676 cache := (ebx & 0xff00) >> 5 // cflush size
677 if cache == 0 && maxExtendedFunction() >= 0x80000006 {
678 _, _, ecx, _ := cpuid(0x80000006)
679 cache = ecx & 0xff // cacheline size
680 }
681 // TODO: Read from Cache and TLB Information
682 return int(cache)
683 }
684
685 func (c *CPUInfo) cacheSize() {
686 c.Cache.L1D = -1
687 c.Cache.L1I = -1
688 c.Cache.L2 = -1
689 c.Cache.L3 = -1
690 vendor := vendorID()
691 switch vendor {
692 case Intel:
693 if maxFunctionID() < 4 {
694 return
695 }
696 for i := uint32(0); ; i++ {
697 eax, ebx, ecx, _ := cpuidex(4, i)
698 cacheType := eax & 15
699 if cacheType == 0 {
700 break
701 }
702 cacheLevel := (eax >> 5) & 7
703 coherency := int(ebx&0xfff) + 1
704 partitions := int((ebx>>12)&0x3ff) + 1
705 associativity := int((ebx>>22)&0x3ff) + 1
706 sets := int(ecx) + 1
707 size := associativity * partitions * coherency * sets
708 switch cacheLevel {
709 case 1:
710 if cacheType == 1 {
711 // 1 = Data Cache
712 c.Cache.L1D = size
713 } else if cacheType == 2 {
714 // 2 = Instruction Cache
715 c.Cache.L1I = size
716 } else {
717 if c.Cache.L1D < 0 {
718 c.Cache.L1I = size
719 }
720 if c.Cache.L1I < 0 {
721 c.Cache.L1I = size
722 }
723 }
724 case 2:
725 c.Cache.L2 = size
726 case 3:
727 c.Cache.L3 = size
728 }
729 }
730 case AMD:
731 // Untested.
732 if maxExtendedFunction() < 0x80000005 {
733 return
734 }
735 _, _, ecx, edx := cpuid(0x80000005)
736 c.Cache.L1D = int(((ecx >> 24) & 0xFF) * 1024)
737 c.Cache.L1I = int(((edx >> 24) & 0xFF) * 1024)
738
739 if maxExtendedFunction() < 0x80000006 {
740 return
741 }
742 _, _, ecx, _ = cpuid(0x80000006)
743 c.Cache.L2 = int(((ecx >> 16) & 0xFFFF) * 1024)
744 }
745
746 return
747 }
748
749 func support() Flags {
750 mfi := maxFunctionID()
751 vend := vendorID()
752 if mfi < 0x1 {
753 return 0
754 }
755 rval := uint64(0)
756 _, _, c, d := cpuid(1)
757 if (d & (1 << 15)) != 0 {
758 rval |= CMOV
759 }
760 if (d & (1 << 23)) != 0 {
761 rval |= MMX
762 }
763 if (d & (1 << 25)) != 0 {
764 rval |= MMXEXT
765 }
766 if (d & (1 << 25)) != 0 {
767 rval |= SSE
768 }
769 if (d & (1 << 26)) != 0 {
770 rval |= SSE2
771 }
772 if (c & 1) != 0 {
773 rval |= SSE3
774 }
775 if (c & 0x00000200) != 0 {
776 rval |= SSSE3
777 }
778 if (c & 0x00080000) != 0 {
779 rval |= SSE4
780 }
781 if (c & 0x00100000) != 0 {
782 rval |= SSE42
783 }
784 if (c & (1 << 25)) != 0 {
785 rval |= AESNI
786 }
787 if (c & (1 << 1)) != 0 {
788 rval |= CLMUL
789 }
790 if c&(1<<23) != 0 {
791 rval |= POPCNT
792 }
793 if c&(1<<30) != 0 {
794 rval |= RDRAND
795 }
796 if c&(1<<29) != 0 {
797 rval |= F16C
798 }
799 if c&(1<<13) != 0 {
800 rval |= CX16
801 }
802 if vend == Intel && (d&(1<<28)) != 0 && mfi >= 4 {
803 if threadsPerCore() > 1 {
804 rval |= HTT
805 }
806 }
807
808 // Check XGETBV, OXSAVE and AVX bits
809 if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 {
810 // Check for OS support
811 eax, _ := xgetbv(0)
812 if (eax & 0x6) == 0x6 {
813 rval |= AVX
814 if (c & 0x00001000) != 0 {
815 rval |= FMA3
816 }
817 }
818 }
819
820 // Check AVX2, AVX2 requires OS support, but BMI1/2 don't.
821 if mfi >= 7 {
822 _, ebx, ecx, _ := cpuidex(7, 0)
823 if (rval&AVX) != 0 && (ebx&0x00000020) != 0 {
824 rval |= AVX2
825 }
826 if (ebx & 0x00000008) != 0 {
827 rval |= BMI1
828 if (ebx & 0x00000100) != 0 {
829 rval |= BMI2
830 }
831 }
832 if ebx&(1<<4) != 0 {
833 rval |= HLE
834 }
835 if ebx&(1<<9) != 0 {
836 rval |= ERMS
837 }
838 if ebx&(1<<11) != 0 {
839 rval |= RTM
840 }
841 if ebx&(1<<14) != 0 {
842 rval |= MPX
843 }
844 if ebx&(1<<18) != 0 {
845 rval |= RDSEED
846 }
847 if ebx&(1<<19) != 0 {
848 rval |= ADX
849 }
850 if ebx&(1<<29) != 0 {
851 rval |= SHA
852 }
853
854 // Only detect AVX-512 features if XGETBV is supported
855 if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) {
856 // Check for OS support
857 eax, _ := xgetbv(0)
858
859 // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and
860 // ZMM16-ZMM31 state are enabled by OS)
861 /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS).
862 if (eax>>5)&7 == 7 && (eax>>1)&3 == 3 {
863 if ebx&(1<<16) != 0 {
864 rval |= AVX512F
865 }
866 if ebx&(1<<17) != 0 {
867 rval |= AVX512DQ
868 }
869 if ebx&(1<<21) != 0 {
870 rval |= AVX512IFMA
871 }
872 if ebx&(1<<26) != 0 {
873 rval |= AVX512PF
874 }
875 if ebx&(1<<27) != 0 {
876 rval |= AVX512ER
877 }
878 if ebx&(1<<28) != 0 {
879 rval |= AVX512CD
880 }
881 if ebx&(1<<30) != 0 {
882 rval |= AVX512BW
883 }
884 if ebx&(1<<31) != 0 {
885 rval |= AVX512VL
886 }
887 // ecx
888 if ecx&(1<<1) != 0 {
889 rval |= AVX512VBMI
890 }
891 }
892 }
893 }
894
895 if maxExtendedFunction() >= 0x80000001 {
896 _, _, c, d := cpuid(0x80000001)
897 if (c & (1 << 5)) != 0 {
898 rval |= LZCNT
899 rval |= POPCNT
900 }
901 if (d & (1 << 31)) != 0 {
902 rval |= AMD3DNOW
903 }
904 if (d & (1 << 30)) != 0 {
905 rval |= AMD3DNOWEXT
906 }
907 if (d & (1 << 23)) != 0 {
908 rval |= MMX
909 }
910 if (d & (1 << 22)) != 0 {
911 rval |= MMXEXT
912 }
913 if (c & (1 << 6)) != 0 {
914 rval |= SSE4A
915 }
916 if d&(1<<20) != 0 {
917 rval |= NX
918 }
919 if d&(1<<27) != 0 {
920 rval |= RDTSCP
921 }
922
923 /* Allow for selectively disabling SSE2 functions on AMD processors
924 with SSE2 support but not SSE4a. This includes Athlon64, some
925 Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster
926 than SSE2 often enough to utilize this special-case flag.
927 AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case
928 so that SSE2 is used unless explicitly disabled by checking
929 AV_CPU_FLAG_SSE2SLOW. */
930 if vendorID() != Intel &&
931 rval&SSE2 != 0 && (c&0x00000040) == 0 {
932 rval |= SSE2SLOW
933 }
934
935 /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be
936 * used unless the OS has AVX support. */
937 if (rval & AVX) != 0 {
938 if (c & 0x00000800) != 0 {
939 rval |= XOP
940 }
941 if (c & 0x00010000) != 0 {
942 rval |= FMA4
943 }
944 }
945
946 if vendorID() == Intel {
947 family, model := familyModel()
948 if family == 6 && (model == 9 || model == 13 || model == 14) {
949 /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and
950 * 6/14 (core1 "yonah") theoretically support sse2, but it's
951 * usually slower than mmx. */
952 if (rval & SSE2) != 0 {
953 rval |= SSE2SLOW
954 }
955 if (rval & SSE3) != 0 {
956 rval |= SSE3SLOW
957 }
958 }
959 /* The Atom processor has SSSE3 support, which is useful in many cases,
960 * but sometimes the SSSE3 version is slower than the SSE2 equivalent
961 * on the Atom, but is generally faster on other processors supporting
962 * SSSE3. This flag allows for selectively disabling certain SSSE3
963 * functions on the Atom. */
964 if family == 6 && model == 28 {
965 rval |= ATOM
966 }
967 }
968 }
969 return Flags(rval)
970 }
971
972 func valAsString(values ...uint32) []byte {
973 r := make([]byte, 4*len(values))
974 for i, v := range values {
975 dst := r[i*4:]
976 dst[0] = byte(v & 0xff)
977 dst[1] = byte((v >> 8) & 0xff)
978 dst[2] = byte((v >> 16) & 0xff)
979 dst[3] = byte((v >> 24) & 0xff)
980 switch {
981 case dst[0] == 0:
982 return r[:i*4]
983 case dst[1] == 0:
984 return r[:i*4+1]
985 case dst[2] == 0:
986 return r[:i*4+2]
987 case dst[3] == 0:
988 return r[:i*4+3]
989 }
990 }
991 return r
992 }
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
3 TEXT ·asmCpuid(SB), 7, $0
4 XORL CX, CX
5 MOVL op+0(FP), AX
6 CPUID
7 MOVL AX, eax+4(FP)
8 MOVL BX, ebx+8(FP)
9 MOVL CX, ecx+12(FP)
10 MOVL DX, edx+16(FP)
11 RET
12
13 // func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
14 TEXT ·asmCpuidex(SB), 7, $0
15 MOVL op+0(FP), AX
16 MOVL op2+4(FP), CX
17 CPUID
18 MOVL AX, eax+8(FP)
19 MOVL BX, ebx+12(FP)
20 MOVL CX, ecx+16(FP)
21 MOVL DX, edx+20(FP)
22 RET
23
24 // func xgetbv(index uint32) (eax, edx uint32)
25 TEXT ·asmXgetbv(SB), 7, $0
26 MOVL index+0(FP), CX
27 BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
28 MOVL AX, eax+4(FP)
29 MOVL DX, edx+8(FP)
30 RET
31
32 // func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
33 TEXT ·asmRdtscpAsm(SB), 7, $0
34 BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
35 MOVL AX, eax+0(FP)
36 MOVL BX, ebx+4(FP)
37 MOVL CX, ecx+8(FP)
38 MOVL DX, edx+12(FP)
39 RET
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
3 TEXT ·asmCpuid(SB), 7, $0
4 XORQ CX, CX
5 MOVL op+0(FP), AX
6 CPUID
7 MOVL AX, eax+8(FP)
8 MOVL BX, ebx+12(FP)
9 MOVL CX, ecx+16(FP)
10 MOVL DX, edx+20(FP)
11 RET
12
13 // func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
14 TEXT ·asmCpuidex(SB), 7, $0
15 MOVL op+0(FP), AX
16 MOVL op2+4(FP), CX
17 CPUID
18 MOVL AX, eax+8(FP)
19 MOVL BX, ebx+12(FP)
20 MOVL CX, ecx+16(FP)
21 MOVL DX, edx+20(FP)
22 RET
23
24 // func asmXgetbv(index uint32) (eax, edx uint32)
25 TEXT ·asmXgetbv(SB), 7, $0
26 MOVL index+0(FP), CX
27 BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
28 MOVL AX, eax+8(FP)
29 MOVL DX, edx+12(FP)
30 RET
31
32 // func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
33 TEXT ·asmRdtscpAsm(SB), 7, $0
34 BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
35 MOVL AX, eax+0(FP)
36 MOVL BX, ebx+4(FP)
37 MOVL CX, ecx+8(FP)
38 MOVL DX, edx+12(FP)
39 RET
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 package cpuid
3
4 import (
5 "fmt"
6 "testing"
7 )
8
9 // There is no real way to test a CPU identifier, since results will
10 // obviously differ on each machine.
11 func TestCPUID(t *testing.T) {
12 n := maxFunctionID()
13 t.Logf("Max Function:0x%x\n", n)
14 n = maxExtendedFunction()
15 t.Logf("Max Extended Function:0x%x\n", n)
16 t.Log("Name:", CPU.BrandName)
17 t.Log("PhysicalCores:", CPU.PhysicalCores)
18 t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
19 t.Log("LogicalCores:", CPU.LogicalCores)
20 t.Log("Family", CPU.Family, "Model:", CPU.Model)
21 t.Log("Features:", CPU.Features)
22 t.Log("Cacheline bytes:", CPU.CacheLine)
23 t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
24 t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
25 t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
26 t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
27
28 if CPU.SSE2() {
29 t.Log("We have SSE2")
30 }
31 }
32
33 func TestDumpCPUID(t *testing.T) {
34 n := int(maxFunctionID())
35 for i := 0; i <= n; i++ {
36 a, b, c, d := cpuidex(uint32(i), 0)
37 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
38 ex := uint32(1)
39 for {
40 a2, b2, c2, d2 := cpuidex(uint32(i), ex)
41 if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 {
42 break
43 }
44 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2)
45 a, b, c, d = a2, b2, c2, d2
46 ex++
47 }
48 }
49 n2 := maxExtendedFunction()
50 for i := uint32(0x80000000); i <= n2; i++ {
51 a, b, c, d := cpuid(i)
52 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
53 }
54 }
55
56 func Example() {
57 // Print basic CPU information:
58 fmt.Println("Name:", CPU.BrandName)
59 fmt.Println("PhysicalCores:", CPU.PhysicalCores)
60 fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
61 fmt.Println("LogicalCores:", CPU.LogicalCores)
62 fmt.Println("Family", CPU.Family, "Model:", CPU.Model)
63 fmt.Println("Features:", CPU.Features)
64 fmt.Println("Cacheline bytes:", CPU.CacheLine)
65
66 // Test if we have a specific feature:
67 if CPU.SSE() {
68 fmt.Println("We have Streaming SIMD Extensions")
69 }
70 }
71
72 func TestBrandNameZero(t *testing.T) {
73 if len(CPU.BrandName) > 0 {
74 // Cut out last byte
75 last := []byte(CPU.BrandName[len(CPU.BrandName)-1:])
76 if last[0] == 0 {
77 t.Fatal("last byte was zero")
78 } else if last[0] == 32 {
79 t.Fatal("whitespace wasn't trimmed")
80 }
81 }
82 }
83
84 // Generated here: http://play.golang.org/p/mko-0tFt0Q
85
86 // TestCmov tests Cmov() function
87 func TestCmov(t *testing.T) {
88 got := CPU.Cmov()
89 expected := CPU.Features&CMOV == CMOV
90 if got != expected {
91 t.Fatalf("Cmov: expected %v, got %v", expected, got)
92 }
93 t.Log("CMOV Support:", got)
94 }
95
96 // TestAmd3dnow tests Amd3dnow() function
97 func TestAmd3dnow(t *testing.T) {
98 got := CPU.Amd3dnow()
99 expected := CPU.Features&AMD3DNOW == AMD3DNOW
100 if got != expected {
101 t.Fatalf("Amd3dnow: expected %v, got %v", expected, got)
102 }
103 t.Log("AMD3DNOW Support:", got)
104 }
105
106 // TestAmd3dnowExt tests Amd3dnowExt() function
107 func TestAmd3dnowExt(t *testing.T) {
108 got := CPU.Amd3dnowExt()
109 expected := CPU.Features&AMD3DNOWEXT == AMD3DNOWEXT
110 if got != expected {
111 t.Fatalf("Amd3dnowExt: expected %v, got %v", expected, got)
112 }
113 t.Log("AMD3DNOWEXT Support:", got)
114 }
115
116 // TestMMX tests MMX() function
117 func TestMMX(t *testing.T) {
118 got := CPU.MMX()
119 expected := CPU.Features&MMX == MMX
120 if got != expected {
121 t.Fatalf("MMX: expected %v, got %v", expected, got)
122 }
123 t.Log("MMX Support:", got)
124 }
125
126 // TestMMXext tests MMXext() function
127 func TestMMXext(t *testing.T) {
128 got := CPU.MMXExt()
129 expected := CPU.Features&MMXEXT == MMXEXT
130 if got != expected {
131 t.Fatalf("MMXExt: expected %v, got %v", expected, got)
132 }
133 t.Log("MMXEXT Support:", got)
134 }
135
136 // TestSSE tests SSE() function
137 func TestSSE(t *testing.T) {
138 got := CPU.SSE()
139 expected := CPU.Features&SSE == SSE
140 if got != expected {
141 t.Fatalf("SSE: expected %v, got %v", expected, got)
142 }
143 t.Log("SSE Support:", got)
144 }
145
146 // TestSSE2 tests SSE2() function
147 func TestSSE2(t *testing.T) {
148 got := CPU.SSE2()
149 expected := CPU.Features&SSE2 == SSE2
150 if got != expected {
151 t.Fatalf("SSE2: expected %v, got %v", expected, got)
152 }
153 t.Log("SSE2 Support:", got)
154 }
155
156 // TestSSE3 tests SSE3() function
157 func TestSSE3(t *testing.T) {
158 got := CPU.SSE3()
159 expected := CPU.Features&SSE3 == SSE3
160 if got != expected {
161 t.Fatalf("SSE3: expected %v, got %v", expected, got)
162 }
163 t.Log("SSE3 Support:", got)
164 }
165
166 // TestSSSE3 tests SSSE3() function
167 func TestSSSE3(t *testing.T) {
168 got := CPU.SSSE3()
169 expected := CPU.Features&SSSE3 == SSSE3
170 if got != expected {
171 t.Fatalf("SSSE3: expected %v, got %v", expected, got)
172 }
173 t.Log("SSSE3 Support:", got)
174 }
175
176 // TestSSE4 tests SSE4() function
177 func TestSSE4(t *testing.T) {
178 got := CPU.SSE4()
179 expected := CPU.Features&SSE4 == SSE4
180 if got != expected {
181 t.Fatalf("SSE4: expected %v, got %v", expected, got)
182 }
183 t.Log("SSE4 Support:", got)
184 }
185
186 // TestSSE42 tests SSE42() function
187 func TestSSE42(t *testing.T) {
188 got := CPU.SSE42()
189 expected := CPU.Features&SSE42 == SSE42
190 if got != expected {
191 t.Fatalf("SSE42: expected %v, got %v", expected, got)
192 }
193 t.Log("SSE42 Support:", got)
194 }
195
196 // TestAVX tests AVX() function
197 func TestAVX(t *testing.T) {
198 got := CPU.AVX()
199 expected := CPU.Features&AVX == AVX
200 if got != expected {
201 t.Fatalf("AVX: expected %v, got %v", expected, got)
202 }
203 t.Log("AVX Support:", got)
204 }
205
206 // TestAVX2 tests AVX2() function
207 func TestAVX2(t *testing.T) {
208 got := CPU.AVX2()
209 expected := CPU.Features&AVX2 == AVX2
210 if got != expected {
211 t.Fatalf("AVX2: expected %v, got %v", expected, got)
212 }
213 t.Log("AVX2 Support:", got)
214 }
215
216 // TestFMA3 tests FMA3() function
217 func TestFMA3(t *testing.T) {
218 got := CPU.FMA3()
219 expected := CPU.Features&FMA3 == FMA3
220 if got != expected {
221 t.Fatalf("FMA3: expected %v, got %v", expected, got)
222 }
223 t.Log("FMA3 Support:", got)
224 }
225
226 // TestFMA4 tests FMA4() function
227 func TestFMA4(t *testing.T) {
228 got := CPU.FMA4()
229 expected := CPU.Features&FMA4 == FMA4
230 if got != expected {
231 t.Fatalf("FMA4: expected %v, got %v", expected, got)
232 }
233 t.Log("FMA4 Support:", got)
234 }
235
236 // TestXOP tests XOP() function
237 func TestXOP(t *testing.T) {
238 got := CPU.XOP()
239 expected := CPU.Features&XOP == XOP
240 if got != expected {
241 t.Fatalf("XOP: expected %v, got %v", expected, got)
242 }
243 t.Log("XOP Support:", got)
244 }
245
246 // TestF16C tests F16C() function
247 func TestF16C(t *testing.T) {
248 got := CPU.F16C()
249 expected := CPU.Features&F16C == F16C
250 if got != expected {
251 t.Fatalf("F16C: expected %v, got %v", expected, got)
252 }
253 t.Log("F16C Support:", got)
254 }
255
256 // TestCX16 tests CX16() function
257 func TestCX16(t *testing.T) {
258 got := CPU.CX16()
259 expected := CPU.Features&CX16 == CX16
260 if got != expected {
261 t.Fatalf("CX16: expected %v, got %v", expected, got)
262 }
263 t.Log("CX16 Support:", got)
264 }
265
266 // TestBMI1 tests BMI1() function
267 func TestBMI1(t *testing.T) {
268 got := CPU.BMI1()
269 expected := CPU.Features&BMI1 == BMI1
270 if got != expected {
271 t.Fatalf("BMI1: expected %v, got %v", expected, got)
272 }
273 t.Log("BMI1 Support:", got)
274 }
275
276 // TestBMI2 tests BMI2() function
277 func TestBMI2(t *testing.T) {
278 got := CPU.BMI2()
279 expected := CPU.Features&BMI2 == BMI2
280 if got != expected {
281 t.Fatalf("BMI2: expected %v, got %v", expected, got)
282 }
283 t.Log("BMI2 Support:", got)
284 }
285
286 // TestTBM tests TBM() function
287 func TestTBM(t *testing.T) {
288 got := CPU.TBM()
289 expected := CPU.Features&TBM == TBM
290 if got != expected {
291 t.Fatalf("TBM: expected %v, got %v", expected, got)
292 }
293 t.Log("TBM Support:", got)
294 }
295
296 // TestLzcnt tests Lzcnt() function
297 func TestLzcnt(t *testing.T) {
298 got := CPU.Lzcnt()
299 expected := CPU.Features&LZCNT == LZCNT
300 if got != expected {
301 t.Fatalf("Lzcnt: expected %v, got %v", expected, got)
302 }
303 t.Log("LZCNT Support:", got)
304 }
305
306 // TestLzcnt tests Lzcnt() function
307 func TestPopcnt(t *testing.T) {
308 got := CPU.Popcnt()
309 expected := CPU.Features&POPCNT == POPCNT
310 if got != expected {
311 t.Fatalf("Popcnt: expected %v, got %v", expected, got)
312 }
313 t.Log("POPCNT Support:", got)
314 }
315
316 // TestAesNi tests AesNi() function
317 func TestAesNi(t *testing.T) {
318 got := CPU.AesNi()
319 expected := CPU.Features&AESNI == AESNI
320 if got != expected {
321 t.Fatalf("AesNi: expected %v, got %v", expected, got)
322 }
323 t.Log("AESNI Support:", got)
324 }
325
326 // TestHTT tests HTT() function
327 func TestHTT(t *testing.T) {
328 got := CPU.HTT()
329 expected := CPU.Features&HTT == HTT
330 if got != expected {
331 t.Fatalf("HTT: expected %v, got %v", expected, got)
332 }
333 t.Log("HTT Support:", got)
334 }
335
336 // TestClmul tests Clmul() function
337 func TestClmul(t *testing.T) {
338 got := CPU.Clmul()
339 expected := CPU.Features&CLMUL == CLMUL
340 if got != expected {
341 t.Fatalf("Clmul: expected %v, got %v", expected, got)
342 }
343 t.Log("CLMUL Support:", got)
344 }
345
346 // TestSSE2Slow tests SSE2Slow() function
347 func TestSSE2Slow(t *testing.T) {
348 got := CPU.SSE2Slow()
349 expected := CPU.Features&SSE2SLOW == SSE2SLOW
350 if got != expected {
351 t.Fatalf("SSE2Slow: expected %v, got %v", expected, got)
352 }
353 t.Log("SSE2SLOW Support:", got)
354 }
355
356 // TestSSE3Slow tests SSE3slow() function
357 func TestSSE3Slow(t *testing.T) {
358 got := CPU.SSE3Slow()
359 expected := CPU.Features&SSE3SLOW == SSE3SLOW
360 if got != expected {
361 t.Fatalf("SSE3slow: expected %v, got %v", expected, got)
362 }
363 t.Log("SSE3SLOW Support:", got)
364 }
365
366 // TestAtom tests Atom() function
367 func TestAtom(t *testing.T) {
368 got := CPU.Atom()
369 expected := CPU.Features&ATOM == ATOM
370 if got != expected {
371 t.Fatalf("Atom: expected %v, got %v", expected, got)
372 }
373 t.Log("ATOM Support:", got)
374 }
375
376 // TestNX tests NX() function (NX (No-Execute) bit)
377 func TestNX(t *testing.T) {
378 got := CPU.NX()
379 expected := CPU.Features&NX == NX
380 if got != expected {
381 t.Fatalf("NX: expected %v, got %v", expected, got)
382 }
383 t.Log("NX Support:", got)
384 }
385
386 // TestSSE4A tests SSE4A() function (AMD Barcelona microarchitecture SSE4a instructions)
387 func TestSSE4A(t *testing.T) {
388 got := CPU.SSE4A()
389 expected := CPU.Features&SSE4A == SSE4A
390 if got != expected {
391 t.Fatalf("SSE4A: expected %v, got %v", expected, got)
392 }
393 t.Log("SSE4A Support:", got)
394 }
395
396 // TestHLE tests HLE() function (Hardware Lock Elision)
397 func TestHLE(t *testing.T) {
398 got := CPU.HLE()
399 expected := CPU.Features&HLE == HLE
400 if got != expected {
401 t.Fatalf("HLE: expected %v, got %v", expected, got)
402 }
403 t.Log("HLE Support:", got)
404 }
405
406 // TestRTM tests RTM() function (Restricted Transactional Memory)
407 func TestRTM(t *testing.T) {
408 got := CPU.RTM()
409 expected := CPU.Features&RTM == RTM
410 if got != expected {
411 t.Fatalf("RTM: expected %v, got %v", expected, got)
412 }
413 t.Log("RTM Support:", got)
414 }
415
416 // TestRdrand tests RDRAND() function (RDRAND instruction is available)
417 func TestRdrand(t *testing.T) {
418 got := CPU.Rdrand()
419 expected := CPU.Features&RDRAND == RDRAND
420 if got != expected {
421 t.Fatalf("Rdrand: expected %v, got %v", expected, got)
422 }
423 t.Log("Rdrand Support:", got)
424 }
425
426 // TestRdseed tests RDSEED() function (RDSEED instruction is available)
427 func TestRdseed(t *testing.T) {
428 got := CPU.Rdseed()
429 expected := CPU.Features&RDSEED == RDSEED
430 if got != expected {
431 t.Fatalf("Rdseed: expected %v, got %v", expected, got)
432 }
433 t.Log("Rdseed Support:", got)
434 }
435
436 // TestADX tests ADX() function (Intel ADX (Multi-Precision Add-Carry Instruction Extensions))
437 func TestADX(t *testing.T) {
438 got := CPU.ADX()
439 expected := CPU.Features&ADX == ADX
440 if got != expected {
441 t.Fatalf("ADX: expected %v, got %v", expected, got)
442 }
443 t.Log("ADX Support:", got)
444 }
445
446 // TestSHA tests SHA() function (Intel SHA Extensions)
447 func TestSHA(t *testing.T) {
448 got := CPU.SHA()
449 expected := CPU.Features&SHA == SHA
450 if got != expected {
451 t.Fatalf("SHA: expected %v, got %v", expected, got)
452 }
453 t.Log("SHA Support:", got)
454 }
455
456 // TestAVX512F tests AVX512F() function (AVX-512 Foundation)
457 func TestAVX512F(t *testing.T) {
458 got := CPU.AVX512F()
459 expected := CPU.Features&AVX512F == AVX512F
460 if got != expected {
461 t.Fatalf("AVX512F: expected %v, got %v", expected, got)
462 }
463 t.Log("AVX512F Support:", got)
464 }
465
466 // TestAVX512DQ tests AVX512DQ() function (AVX-512 Doubleword and Quadword Instructions)
467 func TestAVX512DQ(t *testing.T) {
468 got := CPU.AVX512DQ()
469 expected := CPU.Features&AVX512DQ == AVX512DQ
470 if got != expected {
471 t.Fatalf("AVX512DQ: expected %v, got %v", expected, got)
472 }
473 t.Log("AVX512DQ Support:", got)
474 }
475
476 // TestAVX512IFMA tests AVX512IFMA() function (AVX-512 Integer Fused Multiply-Add Instructions)
477 func TestAVX512IFMA(t *testing.T) {
478 got := CPU.AVX512IFMA()
479 expected := CPU.Features&AVX512IFMA == AVX512IFMA
480 if got != expected {
481 t.Fatalf("AVX512IFMA: expected %v, got %v", expected, got)
482 }
483 t.Log("AVX512IFMA Support:", got)
484 }
485
486 // TestAVX512PF tests AVX512PF() function (AVX-512 Prefetch Instructions)
487 func TestAVX512PF(t *testing.T) {
488 got := CPU.AVX512PF()
489 expected := CPU.Features&AVX512PF == AVX512PF
490 if got != expected {
491 t.Fatalf("AVX512PF: expected %v, got %v", expected, got)
492 }
493 t.Log("AVX512PF Support:", got)
494 }
495
496 // TestAVX512ER tests AVX512ER() function (AVX-512 Exponential and Reciprocal Instructions)
497 func TestAVX512ER(t *testing.T) {
498 got := CPU.AVX512ER()
499 expected := CPU.Features&AVX512ER == AVX512ER
500 if got != expected {
501 t.Fatalf("AVX512ER: expected %v, got %v", expected, got)
502 }
503 t.Log("AVX512ER Support:", got)
504 }
505
506 // TestAVX512CD tests AVX512CD() function (AVX-512 Conflict Detection Instructions)
507 func TestAVX512CD(t *testing.T) {
508 got := CPU.AVX512CD()
509 expected := CPU.Features&AVX512CD == AVX512CD
510 if got != expected {
511 t.Fatalf("AVX512CD: expected %v, got %v", expected, got)
512 }
513 t.Log("AVX512CD Support:", got)
514 }
515
516 // TestAVX512BW tests AVX512BW() function (AVX-512 Byte and Word Instructions)
517 func TestAVX512BW(t *testing.T) {
518 got := CPU.AVX512BW()
519 expected := CPU.Features&AVX512BW == AVX512BW
520 if got != expected {
521 t.Fatalf("AVX512BW: expected %v, got %v", expected, got)
522 }
523 t.Log("AVX512BW Support:", got)
524 }
525
526 // TestAVX512VL tests AVX512VL() function (AVX-512 Vector Length Extensions)
527 func TestAVX512VL(t *testing.T) {
528 got := CPU.AVX512VL()
529 expected := CPU.Features&AVX512VL == AVX512VL
530 if got != expected {
531 t.Fatalf("AVX512VL: expected %v, got %v", expected, got)
532 }
533 t.Log("AVX512VL Support:", got)
534 }
535
536 // TestAVX512VL tests AVX512VBMI() function (AVX-512 Vector Bit Manipulation Instructions)
537 func TestAVX512VBMI(t *testing.T) {
538 got := CPU.AVX512VBMI()
539 expected := CPU.Features&AVX512VBMI == AVX512VBMI
540 if got != expected {
541 t.Fatalf("AVX512VBMI: expected %v, got %v", expected, got)
542 }
543 t.Log("AVX512VBMI Support:", got)
544 }
545
546 // TestMPX tests MPX() function (Intel MPX (Memory Protection Extensions))
547 func TestMPX(t *testing.T) {
548 got := CPU.MPX()
549 expected := CPU.Features&MPX == MPX
550 if got != expected {
551 t.Fatalf("MPX: expected %v, got %v", expected, got)
552 }
553 t.Log("MPX Support:", got)
554 }
555
556 // TestERMS tests ERMS() function (Enhanced REP MOVSB/STOSB)
557 func TestERMS(t *testing.T) {
558 got := CPU.ERMS()
559 expected := CPU.Features&ERMS == ERMS
560 if got != expected {
561 t.Fatalf("ERMS: expected %v, got %v", expected, got)
562 }
563 t.Log("ERMS Support:", got)
564 }
565
566 // TestVendor writes the detected vendor. Will be 0 if unknown
567 func TestVendor(t *testing.T) {
568 t.Log("Vendor ID:", CPU.VendorID)
569 }
570
571 // Intel returns true if vendor is recognized as Intel
572 func TestIntel(t *testing.T) {
573 got := CPU.Intel()
574 expected := CPU.VendorID == Intel
575 if got != expected {
576 t.Fatalf("TestIntel: expected %v, got %v", expected, got)
577 }
578 t.Log("TestIntel:", got)
579 }
580
581 // AMD returns true if vendor is recognized as AMD
582 func TestAMD(t *testing.T) {
583 got := CPU.AMD()
584 expected := CPU.VendorID == AMD
585 if got != expected {
586 t.Fatalf("TestAMD: expected %v, got %v", expected, got)
587 }
588 t.Log("TestAMD:", got)
589 }
590
591 // Transmeta returns true if vendor is recognized as Transmeta
592 func TestTransmeta(t *testing.T) {
593 got := CPU.Transmeta()
594 expected := CPU.VendorID == Transmeta
595 if got != expected {
596 t.Fatalf("TestTransmeta: expected %v, got %v", expected, got)
597 }
598 t.Log("TestTransmeta:", got)
599 }
600
601 // NSC returns true if vendor is recognized as National Semiconductor
602 func TestNSC(t *testing.T) {
603 got := CPU.NSC()
604 expected := CPU.VendorID == NSC
605 if got != expected {
606 t.Fatalf("TestNSC: expected %v, got %v", expected, got)
607 }
608 t.Log("TestNSC:", got)
609 }
610
611 // VIA returns true if vendor is recognized as VIA
612 func TestVIA(t *testing.T) {
613 got := CPU.VIA()
614 expected := CPU.VendorID == VIA
615 if got != expected {
616 t.Fatalf("TestVIA: expected %v, got %v", expected, got)
617 }
618 t.Log("TestVIA:", got)
619 }
620
621 // Test VM function
622 func TestVM(t *testing.T) {
623 t.Log("Vendor ID:", CPU.VM())
624 }
625
626 // Test RTCounter function
627 func TestRtCounter(t *testing.T) {
628 a := CPU.RTCounter()
629 b := CPU.RTCounter()
630 t.Log("CPU Counter:", a, b, b-a)
631 }
632
633 // Prints the value of Ia32TscAux()
634 func TestIa32TscAux(t *testing.T) {
635 ecx := CPU.Ia32TscAux()
636 t.Logf("Ia32TscAux:0x%x\n", ecx)
637 if ecx != 0 {
638 chip := (ecx & 0xFFF000) >> 12
639 core := ecx & 0xFFF
640 t.Log("Likely chip, core:", chip, core)
641 }
642 }
643
644 func TestThreadsPerCoreNZ(t *testing.T) {
645 if CPU.ThreadsPerCore == 0 {
646 t.Fatal("threads per core is zero")
647 }
648 }
649
650 // Prints the value of LogicalCPU()
651 func TestLogicalCPU(t *testing.T) {
652 t.Log("Currently executing on cpu:", CPU.LogicalCPU())
653 }
654
655 func TestMaxFunction(t *testing.T) {
656 expect := maxFunctionID()
657 if CPU.maxFunc != expect {
658 t.Fatal("Max function does not match, expected", expect, "but got", CPU.maxFunc)
659 }
660 expect = maxExtendedFunction()
661 if CPU.maxExFunc != expect {
662 t.Fatal("Max Extended function does not match, expected", expect, "but got", CPU.maxFunc)
663 }
664 }
665
666 // This example will calculate the chip/core number on Linux
667 // Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX.
668 func ExampleCPUInfo_Ia32TscAux(t *testing.T) {
669 ecx := CPU.Ia32TscAux()
670 if ecx == 0 {
671 fmt.Println("Unknown CPU ID")
672 return
673 }
674 chip := (ecx & 0xFFF000) >> 12
675 core := ecx & 0xFFF
676 fmt.Println("Chip, Core:", chip, core)
677 }
678
679 /*
680 func TestPhysical(t *testing.T) {
681 var test16 = "CPUID 00000000: 0000000d-756e6547-6c65746e-49656e69 \nCPUID 00000001: 000206d7-03200800-1fbee3ff-bfebfbff \nCPUID 00000002: 76035a01-00f0b2ff-00000000-00ca0000 \nCPUID 00000003: 00000000-00000000-00000000-00000000 \nCPUID 00000004: 3c004121-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004122-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004143-01c0003f-000001ff-00000000 \nCPUID 00000004: 3c07c163-04c0003f-00003fff-00000006 \nCPUID 00000005: 00000040-00000040-00000003-00021120 \nCPUID 00000006: 00000075-00000002-00000009-00000000 \nCPUID 00000007: 00000000-00000000-00000000-00000000 \nCPUID 00000008: 00000000-00000000-00000000-00000000 \nCPUID 00000009: 00000001-00000000-00000000-00000000 \nCPUID 0000000a: 07300403-00000000-00000000-00000603 \nCPUID 0000000b: 00000000-00000000-00000003-00000003 \nCPUID 0000000b: 00000005-00000010-00000201-00000003 \nCPUID 0000000c: 00000000-00000000-00000000-00000000 \nCPUID 0000000d: 00000007-00000340-00000340-00000000 \nCPUID 0000000d: 00000001-00000000-00000000-00000000 \nCPUID 0000000d: 00000100-00000240-00000000-00000000 \nCPUID 80000000: 80000008-00000000-00000000-00000000 \nCPUID 80000001: 00000000-00000000-00000001-2c100800 \nCPUID 80000002: 20202020-49202020-6c65746e-20295228 \nCPUID 80000003: 6e6f6558-20295228-20555043-322d3545 \nCPUID 80000004: 20303636-20402030-30322e32-007a4847 \nCPUID 80000005: 00000000-00000000-00000000-00000000 \nCPUID 80000006: 00000000-00000000-01006040-00000000 \nCPUID 80000007: 00000000-00000000-00000000-00000100 \nCPUID 80000008: 0000302e-00000000-00000000-00000000"
682 restore := mockCPU([]byte(test16))
683 Detect()
684 t.Log("Name:", CPU.BrandName)
685 n := maxFunctionID()
686 t.Logf("Max Function:0x%x\n", n)
687 n = maxExtendedFunction()
688 t.Logf("Max Extended Function:0x%x\n", n)
689 t.Log("PhysicalCores:", CPU.PhysicalCores)
690 t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
691 t.Log("LogicalCores:", CPU.LogicalCores)
692 t.Log("Family", CPU.Family, "Model:", CPU.Model)
693 t.Log("Features:", CPU.Features)
694 t.Log("Cacheline bytes:", CPU.CacheLine)
695 t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
696 t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
697 t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
698 t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
699 if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 {
700 if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore {
701 t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)",
702 CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore)
703 }
704 }
705
706 if CPU.ThreadsPerCore > 1 && !CPU.HTT() {
707 t.Fatalf("Hyperthreading not detected")
708 }
709 if CPU.ThreadsPerCore == 1 && CPU.HTT() {
710 t.Fatalf("Hyperthreading detected, but only 1 Thread per core")
711 }
712 restore()
713 Detect()
714 TestCPUID(t)
715 }
716 */
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // +build 386 amd64
3
4 package cpuid
5
6 func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
7 func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
8 func asmXgetbv(index uint32) (eax, edx uint32)
9 func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
10
11 func initCPU() {
12 cpuid = asmCpuid
13 cpuidex = asmCpuidex
14 xgetbv = asmXgetbv
15 rdtscpAsm = asmRdtscpAsm
16 }
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // +build !amd64,!386
3
4 package cpuid
5
6 func initCPU() {
7 cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
8 return 0, 0, 0, 0
9 }
10
11 cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
12 return 0, 0, 0, 0
13 }
14
15 xgetbv = func(index uint32) (eax, edx uint32) {
16 return 0, 0
17 }
18
19 rdtscpAsm = func() (eax, ebx, ecx, edx uint32) {
20 return 0, 0, 0, 0
21 }
22 }
0 package cpuid
1
2 //go:generate go run private-gen.go
0 package cpuid
1
2 import (
3 "archive/zip"
4 "fmt"
5 "io/ioutil"
6 "sort"
7 "strings"
8 "testing"
9 )
10
11 type fakecpuid map[uint32][][]uint32
12
13 type idfuncs struct {
14 cpuid func(op uint32) (eax, ebx, ecx, edx uint32)
15 cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32)
16 xgetbv func(index uint32) (eax, edx uint32)
17 }
18
19 func (f fakecpuid) String() string {
20 var out = make([]string, 0, len(f))
21 for key, val := range f {
22 for _, v := range val {
23 out = append(out, fmt.Sprintf("CPUID %08x: [%08x, %08x, %08x, %08x]", key, v[0], v[1], v[2], v[3]))
24 }
25 }
26 sorter := sort.StringSlice(out)
27 sort.Sort(&sorter)
28 return strings.Join(sorter, "\n")
29 }
30
31 func mockCPU(def []byte) func() {
32 lines := strings.Split(string(def), "\n")
33 anyfound := false
34 fakeID := make(fakecpuid)
35 for _, line := range lines {
36 line = strings.Trim(line, "\r\t ")
37 if !strings.HasPrefix(line, "CPUID") {
38 continue
39 }
40 // Only collect for first cpu
41 if strings.HasPrefix(line, "CPUID 00000000") {
42 if anyfound {
43 break
44 }
45 }
46 if !strings.Contains(line, "-") {
47 //continue
48 }
49 items := strings.Split(line, ":")
50 if len(items) < 2 {
51 if len(line) == 51 || len(line) == 50 {
52 items = []string{line[0:14], line[15:]}
53 } else {
54 items = strings.Split(line, "\t")
55 if len(items) != 2 {
56 //fmt.Println("not found:", line, "len:", len(line))
57 continue
58 }
59 }
60 }
61 items = items[0:2]
62 vals := strings.Trim(items[1], "\r\n ")
63
64 var idV uint32
65 n, err := fmt.Sscanf(items[0], "CPUID %x", &idV)
66 if err != nil || n != 1 {
67 continue
68 }
69 existing, ok := fakeID[idV]
70 if !ok {
71 existing = make([][]uint32, 0)
72 }
73
74 values := make([]uint32, 4)
75 n, err = fmt.Sscanf(vals, "%x-%x-%x-%x", &values[0], &values[1], &values[2], &values[3])
76 if n != 4 || err != nil {
77 n, err = fmt.Sscanf(vals, "%x %x %x %x", &values[0], &values[1], &values[2], &values[3])
78 if n != 4 || err != nil {
79 //fmt.Println("scanned", vals, "got", n, "Err:", err)
80 continue
81 }
82 }
83
84 existing = append(existing, values)
85 fakeID[idV] = existing
86 anyfound = true
87 }
88
89 restorer := func(f idfuncs) func() {
90 return func() {
91 cpuid = f.cpuid
92 cpuidex = f.cpuidex
93 xgetbv = f.xgetbv
94 }
95 }(idfuncs{cpuid: cpuid, cpuidex: cpuidex, xgetbv: xgetbv})
96
97 cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
98 if op == 0x80000000 || op == 0 {
99 var ok bool
100 _, ok = fakeID[op]
101 if !ok {
102 return 0, 0, 0, 0
103 }
104 }
105 first, ok := fakeID[op]
106 if !ok {
107 if op > maxFunctionID() {
108 panic(fmt.Sprintf("Base not found: %v, request:%#v\n", fakeID, op))
109 } else {
110 // we have some entries missing
111 return 0, 0, 0, 0
112 }
113 }
114 theid := first[0]
115 return theid[0], theid[1], theid[2], theid[3]
116 }
117 cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
118 if op == 0x80000000 {
119 var ok bool
120 _, ok = fakeID[op]
121 if !ok {
122 return 0, 0, 0, 0
123 }
124 }
125 first, ok := fakeID[op]
126 if !ok {
127 if op > maxExtendedFunction() {
128 panic(fmt.Sprintf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2))
129 } else {
130 // we have some entries missing
131 return 0, 0, 0, 0
132 }
133 }
134 if int(op2) >= len(first) {
135 //fmt.Printf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2)
136 return 0, 0, 0, 0
137 }
138 theid := first[op2]
139 return theid[0], theid[1], theid[2], theid[3]
140 }
141 xgetbv = func(index uint32) (eax, edx uint32) {
142 first, ok := fakeID[1]
143 if !ok {
144 panic(fmt.Sprintf("XGETBV not supported %v", fakeID))
145 }
146 second := first[0]
147 // ECX bit 26 must be set
148 if (second[2] & 1 << 26) == 0 {
149 panic(fmt.Sprintf("XGETBV not supported %v", fakeID))
150 }
151 // We don't have any data to return, unfortunately
152 return 0, 0
153 }
154 return restorer
155 }
156
157 func TestMocks(t *testing.T) {
158 zr, err := zip.OpenReader("testdata/cpuid_data.zip")
159 if err != nil {
160 t.Skip("No testdata:", err)
161 }
162 defer zr.Close()
163 for _, f := range zr.File {
164 rc, err := f.Open()
165 if err != nil {
166 t.Fatal(err)
167 }
168 content, err := ioutil.ReadAll(rc)
169 if err != nil {
170 t.Fatal(err)
171 }
172 rc.Close()
173 t.Log("Opening", f.FileInfo().Name())
174 restore := mockCPU(content)
175 Detect()
176 t.Log("Name:", CPU.BrandName)
177 n := maxFunctionID()
178 t.Logf("Max Function:0x%x\n", n)
179 n = maxExtendedFunction()
180 t.Logf("Max Extended Function:0x%x\n", n)
181 t.Log("PhysicalCores:", CPU.PhysicalCores)
182 t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
183 t.Log("LogicalCores:", CPU.LogicalCores)
184 t.Log("Family", CPU.Family, "Model:", CPU.Model)
185 t.Log("Features:", CPU.Features)
186 t.Log("Cacheline bytes:", CPU.CacheLine)
187 t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
188 t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
189 t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
190 t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
191 if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 {
192 if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore {
193 t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)",
194 CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore)
195 }
196 }
197
198 if CPU.ThreadsPerCore > 1 && !CPU.HTT() {
199 t.Fatalf("Hyperthreading not detected")
200 }
201 if CPU.ThreadsPerCore == 1 && CPU.HTT() {
202 t.Fatalf("Hyperthreading detected, but only 1 Thread per core")
203 }
204 restore()
205 }
206 Detect()
207
208 }
0 # cpuid private
1
2 This is a specially converted of the cpuid package, so it can be included in
3 a package without exporting anything.
4
5 Package home: https://github.com/klauspost/cpuid
0 // Generated, DO NOT EDIT,
1 // but copy it to your own project and rename the package.
2 // See more at http://github.com/klauspost/cpuid
3
4 package cpuid
5
6 import (
7 "strings"
8 )
9
10 // Vendor is a representation of a CPU vendor.
11 type vendor int
12
13 const (
14 other vendor = iota
15 intel
16 amd
17 via
18 transmeta
19 nsc
20 kvm // Kernel-based Virtual Machine
21 msvm // Microsoft Hyper-V or Windows Virtual PC
22 vmware
23 xenhvm
24 )
25
26 const (
27 cmov = 1 << iota // i686 CMOV
28 nx // NX (No-Execute) bit
29 amd3dnow // AMD 3DNOW
30 amd3dnowext // AMD 3DNowExt
31 mmx // standard MMX
32 mmxext // SSE integer functions or AMD MMX ext
33 sse // SSE functions
34 sse2 // P4 SSE functions
35 sse3 // Prescott SSE3 functions
36 ssse3 // Conroe SSSE3 functions
37 sse4 // Penryn SSE4.1 functions
38 sse4a // AMD Barcelona microarchitecture SSE4a instructions
39 sse42 // Nehalem SSE4.2 functions
40 avx // AVX functions
41 avx2 // AVX2 functions
42 fma3 // Intel FMA 3
43 fma4 // Bulldozer FMA4 functions
44 xop // Bulldozer XOP functions
45 f16c // Half-precision floating-point conversion
46 bmi1 // Bit Manipulation Instruction Set 1
47 bmi2 // Bit Manipulation Instruction Set 2
48 tbm // AMD Trailing Bit Manipulation
49 lzcnt // LZCNT instruction
50 popcnt // POPCNT instruction
51 aesni // Advanced Encryption Standard New Instructions
52 clmul // Carry-less Multiplication
53 htt // Hyperthreading (enabled)
54 hle // Hardware Lock Elision
55 rtm // Restricted Transactional Memory
56 rdrand // RDRAND instruction is available
57 rdseed // RDSEED instruction is available
58 adx // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
59 sha // Intel SHA Extensions
60 avx512f // AVX-512 Foundation
61 avx512dq // AVX-512 Doubleword and Quadword Instructions
62 avx512ifma // AVX-512 Integer Fused Multiply-Add Instructions
63 avx512pf // AVX-512 Prefetch Instructions
64 avx512er // AVX-512 Exponential and Reciprocal Instructions
65 avx512cd // AVX-512 Conflict Detection Instructions
66 avx512bw // AVX-512 Byte and Word Instructions
67 avx512vl // AVX-512 Vector Length Extensions
68 avx512vbmi // AVX-512 Vector Bit Manipulation Instructions
69 mpx // Intel MPX (Memory Protection Extensions)
70 erms // Enhanced REP MOVSB/STOSB
71 rdtscp // RDTSCP Instruction
72 cx16 // CMPXCHG16B Instruction
73
74 // Performance indicators
75 sse2slow // SSE2 is supported, but usually not faster
76 sse3slow // SSE3 is supported, but usually not faster
77 atom // Atom processor, some SSSE3 instructions are slower
78 )
79
80 var flagNames = map[flags]string{
81 cmov: "CMOV", // i686 CMOV
82 nx: "NX", // NX (No-Execute) bit
83 amd3dnow: "AMD3DNOW", // AMD 3DNOW
84 amd3dnowext: "AMD3DNOWEXT", // AMD 3DNowExt
85 mmx: "MMX", // Standard MMX
86 mmxext: "MMXEXT", // SSE integer functions or AMD MMX ext
87 sse: "SSE", // SSE functions
88 sse2: "SSE2", // P4 SSE2 functions
89 sse3: "SSE3", // Prescott SSE3 functions
90 ssse3: "SSSE3", // Conroe SSSE3 functions
91 sse4: "SSE4.1", // Penryn SSE4.1 functions
92 sse4a: "SSE4A", // AMD Barcelona microarchitecture SSE4a instructions
93 sse42: "SSE4.2", // Nehalem SSE4.2 functions
94 avx: "AVX", // AVX functions
95 avx2: "AVX2", // AVX functions
96 fma3: "FMA3", // Intel FMA 3
97 fma4: "FMA4", // Bulldozer FMA4 functions
98 xop: "XOP", // Bulldozer XOP functions
99 f16c: "F16C", // Half-precision floating-point conversion
100 bmi1: "BMI1", // Bit Manipulation Instruction Set 1
101 bmi2: "BMI2", // Bit Manipulation Instruction Set 2
102 tbm: "TBM", // AMD Trailing Bit Manipulation
103 lzcnt: "LZCNT", // LZCNT instruction
104 popcnt: "POPCNT", // POPCNT instruction
105 aesni: "AESNI", // Advanced Encryption Standard New Instructions
106 clmul: "CLMUL", // Carry-less Multiplication
107 htt: "HTT", // Hyperthreading (enabled)
108 hle: "HLE", // Hardware Lock Elision
109 rtm: "RTM", // Restricted Transactional Memory
110 rdrand: "RDRAND", // RDRAND instruction is available
111 rdseed: "RDSEED", // RDSEED instruction is available
112 adx: "ADX", // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
113 sha: "SHA", // Intel SHA Extensions
114 avx512f: "AVX512F", // AVX-512 Foundation
115 avx512dq: "AVX512DQ", // AVX-512 Doubleword and Quadword Instructions
116 avx512ifma: "AVX512IFMA", // AVX-512 Integer Fused Multiply-Add Instructions
117 avx512pf: "AVX512PF", // AVX-512 Prefetch Instructions
118 avx512er: "AVX512ER", // AVX-512 Exponential and Reciprocal Instructions
119 avx512cd: "AVX512CD", // AVX-512 Conflict Detection Instructions
120 avx512bw: "AVX512BW", // AVX-512 Byte and Word Instructions
121 avx512vl: "AVX512VL", // AVX-512 Vector Length Extensions
122 avx512vbmi: "AVX512VBMI", // AVX-512 Vector Bit Manipulation Instructions
123 mpx: "MPX", // Intel MPX (Memory Protection Extensions)
124 erms: "ERMS", // Enhanced REP MOVSB/STOSB
125 rdtscp: "RDTSCP", // RDTSCP Instruction
126 cx16: "CX16", // CMPXCHG16B Instruction
127
128 // Performance indicators
129 sse2slow: "SSE2SLOW", // SSE2 supported, but usually not faster
130 sse3slow: "SSE3SLOW", // SSE3 supported, but usually not faster
131 atom: "ATOM", // Atom processor, some SSSE3 instructions are slower
132
133 }
134
135 // CPUInfo contains information about the detected system CPU.
136 type cpuInfo struct {
137 brandname string // Brand name reported by the CPU
138 vendorid vendor // Comparable CPU vendor ID
139 features flags // Features of the CPU
140 physicalcores int // Number of physical processor cores in your CPU. Will be 0 if undetectable.
141 threadspercore int // Number of threads per physical core. Will be 1 if undetectable.
142 logicalcores int // Number of physical cores times threads that can run on each core through the use of hyperthreading. Will be 0 if undetectable.
143 family int // CPU family number
144 model int // CPU model number
145 cacheline int // Cache line size in bytes. Will be 0 if undetectable.
146 cache struct {
147 l1i int // L1 Instruction Cache (per core or shared). Will be -1 if undetected
148 l1d int // L1 Data Cache (per core or shared). Will be -1 if undetected
149 l2 int // L2 Cache (per core or shared). Will be -1 if undetected
150 l3 int // L3 Instruction Cache (per core or shared). Will be -1 if undetected
151 }
152 maxFunc uint32
153 maxExFunc uint32
154 }
155
156 var cpuid func(op uint32) (eax, ebx, ecx, edx uint32)
157 var cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32)
158 var xgetbv func(index uint32) (eax, edx uint32)
159 var rdtscpAsm func() (eax, ebx, ecx, edx uint32)
160
161 // CPU contains information about the CPU as detected on startup,
162 // or when Detect last was called.
163 //
164 // Use this as the primary entry point to you data,
165 // this way queries are
166 var cpu cpuInfo
167
168 func init() {
169 initCPU()
170 detect()
171 }
172
173 // Detect will re-detect current CPU info.
174 // This will replace the content of the exported CPU variable.
175 //
176 // Unless you expect the CPU to change while you are running your program
177 // you should not need to call this function.
178 // If you call this, you must ensure that no other goroutine is accessing the
179 // exported CPU variable.
180 func detect() {
181 cpu.maxFunc = maxFunctionID()
182 cpu.maxExFunc = maxExtendedFunction()
183 cpu.brandname = brandName()
184 cpu.cacheline = cacheLine()
185 cpu.family, cpu.model = familyModel()
186 cpu.features = support()
187 cpu.threadspercore = threadsPerCore()
188 cpu.logicalcores = logicalCores()
189 cpu.physicalcores = physicalCores()
190 cpu.vendorid = vendorID()
191 cpu.cacheSize()
192 }
193
194 // Generated here: http://play.golang.org/p/BxFH2Gdc0G
195
196 // Cmov indicates support of CMOV instructions
197 func (c cpuInfo) cmov() bool {
198 return c.features&cmov != 0
199 }
200
201 // Amd3dnow indicates support of AMD 3DNOW! instructions
202 func (c cpuInfo) amd3dnow() bool {
203 return c.features&amd3dnow != 0
204 }
205
206 // Amd3dnowExt indicates support of AMD 3DNOW! Extended instructions
207 func (c cpuInfo) amd3dnowext() bool {
208 return c.features&amd3dnowext != 0
209 }
210
211 // MMX indicates support of MMX instructions
212 func (c cpuInfo) mmx() bool {
213 return c.features&mmx != 0
214 }
215
216 // MMXExt indicates support of MMXEXT instructions
217 // (SSE integer functions or AMD MMX ext)
218 func (c cpuInfo) mmxext() bool {
219 return c.features&mmxext != 0
220 }
221
222 // SSE indicates support of SSE instructions
223 func (c cpuInfo) sse() bool {
224 return c.features&sse != 0
225 }
226
227 // SSE2 indicates support of SSE 2 instructions
228 func (c cpuInfo) sse2() bool {
229 return c.features&sse2 != 0
230 }
231
232 // SSE3 indicates support of SSE 3 instructions
233 func (c cpuInfo) sse3() bool {
234 return c.features&sse3 != 0
235 }
236
237 // SSSE3 indicates support of SSSE 3 instructions
238 func (c cpuInfo) ssse3() bool {
239 return c.features&ssse3 != 0
240 }
241
242 // SSE4 indicates support of SSE 4 (also called SSE 4.1) instructions
243 func (c cpuInfo) sse4() bool {
244 return c.features&sse4 != 0
245 }
246
247 // SSE42 indicates support of SSE4.2 instructions
248 func (c cpuInfo) sse42() bool {
249 return c.features&sse42 != 0
250 }
251
252 // AVX indicates support of AVX instructions
253 // and operating system support of AVX instructions
254 func (c cpuInfo) avx() bool {
255 return c.features&avx != 0
256 }
257
258 // AVX2 indicates support of AVX2 instructions
259 func (c cpuInfo) avx2() bool {
260 return c.features&avx2 != 0
261 }
262
263 // FMA3 indicates support of FMA3 instructions
264 func (c cpuInfo) fma3() bool {
265 return c.features&fma3 != 0
266 }
267
268 // FMA4 indicates support of FMA4 instructions
269 func (c cpuInfo) fma4() bool {
270 return c.features&fma4 != 0
271 }
272
273 // XOP indicates support of XOP instructions
274 func (c cpuInfo) xop() bool {
275 return c.features&xop != 0
276 }
277
278 // F16C indicates support of F16C instructions
279 func (c cpuInfo) f16c() bool {
280 return c.features&f16c != 0
281 }
282
283 // BMI1 indicates support of BMI1 instructions
284 func (c cpuInfo) bmi1() bool {
285 return c.features&bmi1 != 0
286 }
287
288 // BMI2 indicates support of BMI2 instructions
289 func (c cpuInfo) bmi2() bool {
290 return c.features&bmi2 != 0
291 }
292
293 // TBM indicates support of TBM instructions
294 // (AMD Trailing Bit Manipulation)
295 func (c cpuInfo) tbm() bool {
296 return c.features&tbm != 0
297 }
298
299 // Lzcnt indicates support of LZCNT instruction
300 func (c cpuInfo) lzcnt() bool {
301 return c.features&lzcnt != 0
302 }
303
304 // Popcnt indicates support of POPCNT instruction
305 func (c cpuInfo) popcnt() bool {
306 return c.features&popcnt != 0
307 }
308
309 // HTT indicates the processor has Hyperthreading enabled
310 func (c cpuInfo) htt() bool {
311 return c.features&htt != 0
312 }
313
314 // SSE2Slow indicates that SSE2 may be slow on this processor
315 func (c cpuInfo) sse2slow() bool {
316 return c.features&sse2slow != 0
317 }
318
319 // SSE3Slow indicates that SSE3 may be slow on this processor
320 func (c cpuInfo) sse3slow() bool {
321 return c.features&sse3slow != 0
322 }
323
324 // AesNi indicates support of AES-NI instructions
325 // (Advanced Encryption Standard New Instructions)
326 func (c cpuInfo) aesni() bool {
327 return c.features&aesni != 0
328 }
329
330 // Clmul indicates support of CLMUL instructions
331 // (Carry-less Multiplication)
332 func (c cpuInfo) clmul() bool {
333 return c.features&clmul != 0
334 }
335
336 // NX indicates support of NX (No-Execute) bit
337 func (c cpuInfo) nx() bool {
338 return c.features&nx != 0
339 }
340
341 // SSE4A indicates support of AMD Barcelona microarchitecture SSE4a instructions
342 func (c cpuInfo) sse4a() bool {
343 return c.features&sse4a != 0
344 }
345
346 // HLE indicates support of Hardware Lock Elision
347 func (c cpuInfo) hle() bool {
348 return c.features&hle != 0
349 }
350
351 // RTM indicates support of Restricted Transactional Memory
352 func (c cpuInfo) rtm() bool {
353 return c.features&rtm != 0
354 }
355
356 // Rdrand indicates support of RDRAND instruction is available
357 func (c cpuInfo) rdrand() bool {
358 return c.features&rdrand != 0
359 }
360
361 // Rdseed indicates support of RDSEED instruction is available
362 func (c cpuInfo) rdseed() bool {
363 return c.features&rdseed != 0
364 }
365
366 // ADX indicates support of Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
367 func (c cpuInfo) adx() bool {
368 return c.features&adx != 0
369 }
370
371 // SHA indicates support of Intel SHA Extensions
372 func (c cpuInfo) sha() bool {
373 return c.features&sha != 0
374 }
375
376 // AVX512F indicates support of AVX-512 Foundation
377 func (c cpuInfo) avx512f() bool {
378 return c.features&avx512f != 0
379 }
380
381 // AVX512DQ indicates support of AVX-512 Doubleword and Quadword Instructions
382 func (c cpuInfo) avx512dq() bool {
383 return c.features&avx512dq != 0
384 }
385
386 // AVX512IFMA indicates support of AVX-512 Integer Fused Multiply-Add Instructions
387 func (c cpuInfo) avx512ifma() bool {
388 return c.features&avx512ifma != 0
389 }
390
391 // AVX512PF indicates support of AVX-512 Prefetch Instructions
392 func (c cpuInfo) avx512pf() bool {
393 return c.features&avx512pf != 0
394 }
395
396 // AVX512ER indicates support of AVX-512 Exponential and Reciprocal Instructions
397 func (c cpuInfo) avx512er() bool {
398 return c.features&avx512er != 0
399 }
400
401 // AVX512CD indicates support of AVX-512 Conflict Detection Instructions
402 func (c cpuInfo) avx512cd() bool {
403 return c.features&avx512cd != 0
404 }
405
406 // AVX512BW indicates support of AVX-512 Byte and Word Instructions
407 func (c cpuInfo) avx512bw() bool {
408 return c.features&avx512bw != 0
409 }
410
411 // AVX512VL indicates support of AVX-512 Vector Length Extensions
412 func (c cpuInfo) avx512vl() bool {
413 return c.features&avx512vl != 0
414 }
415
416 // AVX512VBMI indicates support of AVX-512 Vector Bit Manipulation Instructions
417 func (c cpuInfo) avx512vbmi() bool {
418 return c.features&avx512vbmi != 0
419 }
420
421 // MPX indicates support of Intel MPX (Memory Protection Extensions)
422 func (c cpuInfo) mpx() bool {
423 return c.features&mpx != 0
424 }
425
426 // ERMS indicates support of Enhanced REP MOVSB/STOSB
427 func (c cpuInfo) erms() bool {
428 return c.features&erms != 0
429 }
430
431 func (c cpuInfo) rdtscp() bool {
432 return c.features&rdtscp != 0
433 }
434
435 func (c cpuInfo) cx16() bool {
436 return c.features&cx16 != 0
437 }
438
439 // Atom indicates an Atom processor
440 func (c cpuInfo) atom() bool {
441 return c.features&atom != 0
442 }
443
444 // Intel returns true if vendor is recognized as Intel
445 func (c cpuInfo) intel() bool {
446 return c.vendorid == intel
447 }
448
449 // AMD returns true if vendor is recognized as AMD
450 func (c cpuInfo) amd() bool {
451 return c.vendorid == amd
452 }
453
454 // Transmeta returns true if vendor is recognized as Transmeta
455 func (c cpuInfo) transmeta() bool {
456 return c.vendorid == transmeta
457 }
458
459 // NSC returns true if vendor is recognized as National Semiconductor
460 func (c cpuInfo) nsc() bool {
461 return c.vendorid == nsc
462 }
463
464 // VIA returns true if vendor is recognized as VIA
465 func (c cpuInfo) via() bool {
466 return c.vendorid == via
467 }
468
469 // RTCounter returns the 64-bit time-stamp counter
470 // Uses the RDTSCP instruction. The value 0 is returned
471 // if the CPU does not support the instruction.
472 func (c cpuInfo) rtcounter() uint64 {
473 if !c.rdtscp() {
474 return 0
475 }
476 a, _, _, d := rdtscpAsm()
477 return uint64(a) | (uint64(d) << 32)
478 }
479
480 // Ia32TscAux returns the IA32_TSC_AUX part of the RDTSCP.
481 // This variable is OS dependent, but on Linux contains information
482 // about the current cpu/core the code is running on.
483 // If the RDTSCP instruction isn't supported on the CPU, the value 0 is returned.
484 func (c cpuInfo) ia32tscaux() uint32 {
485 if !c.rdtscp() {
486 return 0
487 }
488 _, _, ecx, _ := rdtscpAsm()
489 return ecx
490 }
491
492 // LogicalCPU will return the Logical CPU the code is currently executing on.
493 // This is likely to change when the OS re-schedules the running thread
494 // to another CPU.
495 // If the current core cannot be detected, -1 will be returned.
496 func (c cpuInfo) logicalcpu() int {
497 if c.maxFunc < 1 {
498 return -1
499 }
500 _, ebx, _, _ := cpuid(1)
501 return int(ebx >> 24)
502 }
503
504 // VM Will return true if the cpu id indicates we are in
505 // a virtual machine. This is only a hint, and will very likely
506 // have many false negatives.
507 func (c cpuInfo) vm() bool {
508 switch c.vendorid {
509 case msvm, kvm, vmware, xenhvm:
510 return true
511 }
512 return false
513 }
514
515 // Flags contains detected cpu features and caracteristics
516 type flags uint64
517
518 // String returns a string representation of the detected
519 // CPU features.
520 func (f flags) String() string {
521 return strings.Join(f.strings(), ",")
522 }
523
524 // Strings returns and array of the detected features.
525 func (f flags) strings() []string {
526 s := support()
527 r := make([]string, 0, 20)
528 for i := uint(0); i < 64; i++ {
529 key := flags(1 << i)
530 val := flagNames[key]
531 if s&key != 0 {
532 r = append(r, val)
533 }
534 }
535 return r
536 }
537
538 func maxExtendedFunction() uint32 {
539 eax, _, _, _ := cpuid(0x80000000)
540 return eax
541 }
542
543 func maxFunctionID() uint32 {
544 a, _, _, _ := cpuid(0)
545 return a
546 }
547
548 func brandName() string {
549 if maxExtendedFunction() >= 0x80000004 {
550 v := make([]uint32, 0, 48)
551 for i := uint32(0); i < 3; i++ {
552 a, b, c, d := cpuid(0x80000002 + i)
553 v = append(v, a, b, c, d)
554 }
555 return strings.Trim(string(valAsString(v...)), " ")
556 }
557 return "unknown"
558 }
559
560 func threadsPerCore() int {
561 mfi := maxFunctionID()
562 if mfi < 0x4 || vendorID() != intel {
563 return 1
564 }
565
566 if mfi < 0xb {
567 _, b, _, d := cpuid(1)
568 if (d & (1 << 28)) != 0 {
569 // v will contain logical core count
570 v := (b >> 16) & 255
571 if v > 1 {
572 a4, _, _, _ := cpuid(4)
573 // physical cores
574 v2 := (a4 >> 26) + 1
575 if v2 > 0 {
576 return int(v) / int(v2)
577 }
578 }
579 }
580 return 1
581 }
582 _, b, _, _ := cpuidex(0xb, 0)
583 if b&0xffff == 0 {
584 return 1
585 }
586 return int(b & 0xffff)
587 }
588
589 func logicalCores() int {
590 mfi := maxFunctionID()
591 switch vendorID() {
592 case intel:
593 // Use this on old Intel processors
594 if mfi < 0xb {
595 if mfi < 1 {
596 return 0
597 }
598 // CPUID.1:EBX[23:16] represents the maximum number of addressable IDs (initial APIC ID)
599 // that can be assigned to logical processors in a physical package.
600 // The value may not be the same as the number of logical processors that are present in the hardware of a physical package.
601 _, ebx, _, _ := cpuid(1)
602 logical := (ebx >> 16) & 0xff
603 return int(logical)
604 }
605 _, b, _, _ := cpuidex(0xb, 1)
606 return int(b & 0xffff)
607 case amd:
608 _, b, _, _ := cpuid(1)
609 return int((b >> 16) & 0xff)
610 default:
611 return 0
612 }
613 }
614
615 func familyModel() (int, int) {
616 if maxFunctionID() < 0x1 {
617 return 0, 0
618 }
619 eax, _, _, _ := cpuid(1)
620 family := ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff)
621 model := ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0)
622 return int(family), int(model)
623 }
624
625 func physicalCores() int {
626 switch vendorID() {
627 case intel:
628 return logicalCores() / threadsPerCore()
629 case amd:
630 if maxExtendedFunction() >= 0x80000008 {
631 _, _, c, _ := cpuid(0x80000008)
632 return int(c&0xff) + 1
633 }
634 }
635 return 0
636 }
637
638 // Except from http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID
639 var vendorMapping = map[string]vendor{
640 "AMDisbetter!": amd,
641 "AuthenticAMD": amd,
642 "CentaurHauls": via,
643 "GenuineIntel": intel,
644 "TransmetaCPU": transmeta,
645 "GenuineTMx86": transmeta,
646 "Geode by NSC": nsc,
647 "VIA VIA VIA ": via,
648 "KVMKVMKVMKVM": kvm,
649 "Microsoft Hv": msvm,
650 "VMwareVMware": vmware,
651 "XenVMMXenVMM": xenhvm,
652 }
653
654 func vendorID() vendor {
655 _, b, c, d := cpuid(0)
656 v := valAsString(b, d, c)
657 vend, ok := vendorMapping[string(v)]
658 if !ok {
659 return other
660 }
661 return vend
662 }
663
664 func cacheLine() int {
665 if maxFunctionID() < 0x1 {
666 return 0
667 }
668
669 _, ebx, _, _ := cpuid(1)
670 cache := (ebx & 0xff00) >> 5 // cflush size
671 if cache == 0 && maxExtendedFunction() >= 0x80000006 {
672 _, _, ecx, _ := cpuid(0x80000006)
673 cache = ecx & 0xff // cacheline size
674 }
675 // TODO: Read from Cache and TLB Information
676 return int(cache)
677 }
678
679 func (c *cpuInfo) cacheSize() {
680 c.cache.l1d = -1
681 c.cache.l1i = -1
682 c.cache.l2 = -1
683 c.cache.l3 = -1
684 vendor := vendorID()
685 switch vendor {
686 case intel:
687 if maxFunctionID() < 4 {
688 return
689 }
690 for i := uint32(0); ; i++ {
691 eax, ebx, ecx, _ := cpuidex(4, i)
692 cacheType := eax & 15
693 if cacheType == 0 {
694 break
695 }
696 cacheLevel := (eax >> 5) & 7
697 coherency := int(ebx&0xfff) + 1
698 partitions := int((ebx>>12)&0x3ff) + 1
699 associativity := int((ebx>>22)&0x3ff) + 1
700 sets := int(ecx) + 1
701 size := associativity * partitions * coherency * sets
702 switch cacheLevel {
703 case 1:
704 if cacheType == 1 {
705 // 1 = Data Cache
706 c.cache.l1d = size
707 } else if cacheType == 2 {
708 // 2 = Instruction Cache
709 c.cache.l1i = size
710 } else {
711 if c.cache.l1d < 0 {
712 c.cache.l1i = size
713 }
714 if c.cache.l1i < 0 {
715 c.cache.l1i = size
716 }
717 }
718 case 2:
719 c.cache.l2 = size
720 case 3:
721 c.cache.l3 = size
722 }
723 }
724 case amd:
725 // Untested.
726 if maxExtendedFunction() < 0x80000005 {
727 return
728 }
729 _, _, ecx, edx := cpuid(0x80000005)
730 c.cache.l1d = int(((ecx >> 24) & 0xFF) * 1024)
731 c.cache.l1i = int(((edx >> 24) & 0xFF) * 1024)
732
733 if maxExtendedFunction() < 0x80000006 {
734 return
735 }
736 _, _, ecx, _ = cpuid(0x80000006)
737 c.cache.l2 = int(((ecx >> 16) & 0xFFFF) * 1024)
738 }
739
740 return
741 }
742
743 func support() flags {
744 mfi := maxFunctionID()
745 vend := vendorID()
746 if mfi < 0x1 {
747 return 0
748 }
749 rval := uint64(0)
750 _, _, c, d := cpuid(1)
751 if (d & (1 << 15)) != 0 {
752 rval |= cmov
753 }
754 if (d & (1 << 23)) != 0 {
755 rval |= mmx
756 }
757 if (d & (1 << 25)) != 0 {
758 rval |= mmxext
759 }
760 if (d & (1 << 25)) != 0 {
761 rval |= sse
762 }
763 if (d & (1 << 26)) != 0 {
764 rval |= sse2
765 }
766 if (c & 1) != 0 {
767 rval |= sse3
768 }
769 if (c & 0x00000200) != 0 {
770 rval |= ssse3
771 }
772 if (c & 0x00080000) != 0 {
773 rval |= sse4
774 }
775 if (c & 0x00100000) != 0 {
776 rval |= sse42
777 }
778 if (c & (1 << 25)) != 0 {
779 rval |= aesni
780 }
781 if (c & (1 << 1)) != 0 {
782 rval |= clmul
783 }
784 if c&(1<<23) != 0 {
785 rval |= popcnt
786 }
787 if c&(1<<30) != 0 {
788 rval |= rdrand
789 }
790 if c&(1<<29) != 0 {
791 rval |= f16c
792 }
793 if c&(1<<13) != 0 {
794 rval |= cx16
795 }
796 if vend == intel && (d&(1<<28)) != 0 && mfi >= 4 {
797 if threadsPerCore() > 1 {
798 rval |= htt
799 }
800 }
801
802 // Check XGETBV, OXSAVE and AVX bits
803 if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 {
804 // Check for OS support
805 eax, _ := xgetbv(0)
806 if (eax & 0x6) == 0x6 {
807 rval |= avx
808 if (c & 0x00001000) != 0 {
809 rval |= fma3
810 }
811 }
812 }
813
814 // Check AVX2, AVX2 requires OS support, but BMI1/2 don't.
815 if mfi >= 7 {
816 _, ebx, ecx, _ := cpuidex(7, 0)
817 if (rval&avx) != 0 && (ebx&0x00000020) != 0 {
818 rval |= avx2
819 }
820 if (ebx & 0x00000008) != 0 {
821 rval |= bmi1
822 if (ebx & 0x00000100) != 0 {
823 rval |= bmi2
824 }
825 }
826 if ebx&(1<<4) != 0 {
827 rval |= hle
828 }
829 if ebx&(1<<9) != 0 {
830 rval |= erms
831 }
832 if ebx&(1<<11) != 0 {
833 rval |= rtm
834 }
835 if ebx&(1<<14) != 0 {
836 rval |= mpx
837 }
838 if ebx&(1<<18) != 0 {
839 rval |= rdseed
840 }
841 if ebx&(1<<19) != 0 {
842 rval |= adx
843 }
844 if ebx&(1<<29) != 0 {
845 rval |= sha
846 }
847
848 // Only detect AVX-512 features if XGETBV is supported
849 if c&((1<<26)|(1<<27)) == (1<<26)|(1<<27) {
850 // Check for OS support
851 eax, _ := xgetbv(0)
852
853 // Verify that XCR0[7:5] = ‘111b’ (OPMASK state, upper 256-bit of ZMM0-ZMM15 and
854 // ZMM16-ZMM31 state are enabled by OS)
855 /// and that XCR0[2:1] = ‘11b’ (XMM state and YMM state are enabled by OS).
856 if (eax>>5)&7 == 7 && (eax>>1)&3 == 3 {
857 if ebx&(1<<16) != 0 {
858 rval |= avx512f
859 }
860 if ebx&(1<<17) != 0 {
861 rval |= avx512dq
862 }
863 if ebx&(1<<21) != 0 {
864 rval |= avx512ifma
865 }
866 if ebx&(1<<26) != 0 {
867 rval |= avx512pf
868 }
869 if ebx&(1<<27) != 0 {
870 rval |= avx512er
871 }
872 if ebx&(1<<28) != 0 {
873 rval |= avx512cd
874 }
875 if ebx&(1<<30) != 0 {
876 rval |= avx512bw
877 }
878 if ebx&(1<<31) != 0 {
879 rval |= avx512vl
880 }
881 // ecx
882 if ecx&(1<<1) != 0 {
883 rval |= avx512vbmi
884 }
885 }
886 }
887 }
888
889 if maxExtendedFunction() >= 0x80000001 {
890 _, _, c, d := cpuid(0x80000001)
891 if (c & (1 << 5)) != 0 {
892 rval |= lzcnt
893 rval |= popcnt
894 }
895 if (d & (1 << 31)) != 0 {
896 rval |= amd3dnow
897 }
898 if (d & (1 << 30)) != 0 {
899 rval |= amd3dnowext
900 }
901 if (d & (1 << 23)) != 0 {
902 rval |= mmx
903 }
904 if (d & (1 << 22)) != 0 {
905 rval |= mmxext
906 }
907 if (c & (1 << 6)) != 0 {
908 rval |= sse4a
909 }
910 if d&(1<<20) != 0 {
911 rval |= nx
912 }
913 if d&(1<<27) != 0 {
914 rval |= rdtscp
915 }
916
917 /* Allow for selectively disabling SSE2 functions on AMD processors
918 with SSE2 support but not SSE4a. This includes Athlon64, some
919 Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster
920 than SSE2 often enough to utilize this special-case flag.
921 AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case
922 so that SSE2 is used unless explicitly disabled by checking
923 AV_CPU_FLAG_SSE2SLOW. */
924 if vendorID() != intel &&
925 rval&sse2 != 0 && (c&0x00000040) == 0 {
926 rval |= sse2slow
927 }
928
929 /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be
930 * used unless the OS has AVX support. */
931 if (rval & avx) != 0 {
932 if (c & 0x00000800) != 0 {
933 rval |= xop
934 }
935 if (c & 0x00010000) != 0 {
936 rval |= fma4
937 }
938 }
939
940 if vendorID() == intel {
941 family, model := familyModel()
942 if family == 6 && (model == 9 || model == 13 || model == 14) {
943 /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and
944 * 6/14 (core1 "yonah") theoretically support sse2, but it's
945 * usually slower than mmx. */
946 if (rval & sse2) != 0 {
947 rval |= sse2slow
948 }
949 if (rval & sse3) != 0 {
950 rval |= sse3slow
951 }
952 }
953 /* The Atom processor has SSSE3 support, which is useful in many cases,
954 * but sometimes the SSSE3 version is slower than the SSE2 equivalent
955 * on the Atom, but is generally faster on other processors supporting
956 * SSSE3. This flag allows for selectively disabling certain SSSE3
957 * functions on the Atom. */
958 if family == 6 && model == 28 {
959 rval |= atom
960 }
961 }
962 }
963 return flags(rval)
964 }
965
966 func valAsString(values ...uint32) []byte {
967 r := make([]byte, 4*len(values))
968 for i, v := range values {
969 dst := r[i*4:]
970 dst[0] = byte(v & 0xff)
971 dst[1] = byte((v >> 8) & 0xff)
972 dst[2] = byte((v >> 16) & 0xff)
973 dst[3] = byte((v >> 24) & 0xff)
974 switch {
975 case dst[0] == 0:
976 return r[:i*4]
977 case dst[1] == 0:
978 return r[:i*4+1]
979 case dst[2] == 0:
980 return r[:i*4+2]
981 case dst[3] == 0:
982 return r[:i*4+3]
983 }
984 }
985 return r
986 }
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
3 TEXT ·asmCpuid(SB), 7, $0
4 XORL CX, CX
5 MOVL op+0(FP), AX
6 CPUID
7 MOVL AX, eax+4(FP)
8 MOVL BX, ebx+8(FP)
9 MOVL CX, ecx+12(FP)
10 MOVL DX, edx+16(FP)
11 RET
12
13 // func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
14 TEXT ·asmCpuidex(SB), 7, $0
15 MOVL op+0(FP), AX
16 MOVL op2+4(FP), CX
17 CPUID
18 MOVL AX, eax+8(FP)
19 MOVL BX, ebx+12(FP)
20 MOVL CX, ecx+16(FP)
21 MOVL DX, edx+20(FP)
22 RET
23
24 // func xgetbv(index uint32) (eax, edx uint32)
25 TEXT ·asmXgetbv(SB), 7, $0
26 MOVL index+0(FP), CX
27 BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
28 MOVL AX, eax+4(FP)
29 MOVL DX, edx+8(FP)
30 RET
31
32 // func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
33 TEXT ·asmRdtscpAsm(SB), 7, $0
34 BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
35 MOVL AX, eax+0(FP)
36 MOVL BX, ebx+4(FP)
37 MOVL CX, ecx+8(FP)
38 MOVL DX, edx+12(FP)
39 RET
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
3 TEXT ·asmCpuid(SB), 7, $0
4 XORQ CX, CX
5 MOVL op+0(FP), AX
6 CPUID
7 MOVL AX, eax+8(FP)
8 MOVL BX, ebx+12(FP)
9 MOVL CX, ecx+16(FP)
10 MOVL DX, edx+20(FP)
11 RET
12
13 // func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
14 TEXT ·asmCpuidex(SB), 7, $0
15 MOVL op+0(FP), AX
16 MOVL op2+4(FP), CX
17 CPUID
18 MOVL AX, eax+8(FP)
19 MOVL BX, ebx+12(FP)
20 MOVL CX, ecx+16(FP)
21 MOVL DX, edx+20(FP)
22 RET
23
24 // func asmXgetbv(index uint32) (eax, edx uint32)
25 TEXT ·asmXgetbv(SB), 7, $0
26 MOVL index+0(FP), CX
27 BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
28 MOVL AX, eax+8(FP)
29 MOVL DX, edx+12(FP)
30 RET
31
32 // func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
33 TEXT ·asmRdtscpAsm(SB), 7, $0
34 BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
35 MOVL AX, eax+0(FP)
36 MOVL BX, ebx+4(FP)
37 MOVL CX, ecx+8(FP)
38 MOVL DX, edx+12(FP)
39 RET
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // +build 386 amd64
3
4 package cpuid
5
6 func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
7 func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
8 func asmXgetbv(index uint32) (eax, edx uint32)
9 func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
10
11 func initCPU() {
12 cpuid = asmCpuid
13 cpuidex = asmCpuidex
14 xgetbv = asmXgetbv
15 rdtscpAsm = asmRdtscpAsm
16 }
0 // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
1
2 // +build !amd64,!386
3
4 package cpuid
5
6 func initCPU() {
7 cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
8 return 0, 0, 0, 0
9 }
10
11 cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
12 return 0, 0, 0, 0
13 }
14
15 xgetbv = func(index uint32) (eax, edx uint32) {
16 return 0, 0
17 }
18
19 rdtscpAsm = func() (eax, ebx, ecx, edx uint32) {
20 return 0, 0, 0, 0
21 }
22 }
0 // Generated, DO NOT EDIT,
1 // but copy it to your own project and rename the package.
2 // See more at http://github.com/klauspost/cpuid
3
4 package cpuid
5
6 import (
7 "fmt"
8 "testing"
9 )
10
11 // There is no real way to test a CPU identifier, since results will
12 // obviously differ on each machine.
13 func TestCPUID(t *testing.T) {
14 n := maxFunctionID()
15 t.Logf("Max Function:0x%x\n", n)
16 n = maxExtendedFunction()
17 t.Logf("Max Extended Function:0x%x\n", n)
18 t.Log("Name:", cpu.brandname)
19 t.Log("PhysicalCores:", cpu.physicalcores)
20 t.Log("ThreadsPerCore:", cpu.threadspercore)
21 t.Log("LogicalCores:", cpu.logicalcores)
22 t.Log("Family", cpu.family, "Model:", cpu.model)
23 t.Log("Features:", cpu.features)
24 t.Log("Cacheline bytes:", cpu.cacheline)
25 t.Log("L1 Instruction Cache:", cpu.cache.l1i, "bytes")
26 t.Log("L1 Data Cache:", cpu.cache.l1d, "bytes")
27 t.Log("L2 Cache:", cpu.cache.l2, "bytes")
28 t.Log("L3 Cache:", cpu.cache.l3, "bytes")
29
30 if cpu.sse2() {
31 t.Log("We have SSE2")
32 }
33 }
34
35 func TestDumpCPUID(t *testing.T) {
36 n := int(maxFunctionID())
37 for i := 0; i <= n; i++ {
38 a, b, c, d := cpuidex(uint32(i), 0)
39 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
40 ex := uint32(1)
41 for {
42 a2, b2, c2, d2 := cpuidex(uint32(i), ex)
43 if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 {
44 break
45 }
46 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2)
47 a, b, c, d = a2, b2, c2, d2
48 ex++
49 }
50 }
51 n2 := maxExtendedFunction()
52 for i := uint32(0x80000000); i <= n2; i++ {
53 a, b, c, d := cpuid(i)
54 t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
55 }
56 }
57
58 func example() {
59 // Print basic CPU information:
60 fmt.Println("Name:", cpu.brandname)
61 fmt.Println("PhysicalCores:", cpu.physicalcores)
62 fmt.Println("ThreadsPerCore:", cpu.threadspercore)
63 fmt.Println("LogicalCores:", cpu.logicalcores)
64 fmt.Println("Family", cpu.family, "Model:", cpu.model)
65 fmt.Println("Features:", cpu.features)
66 fmt.Println("Cacheline bytes:", cpu.cacheline)
67
68 // Test if we have a specific feature:
69 if cpu.sse() {
70 fmt.Println("We have Streaming SIMD Extensions")
71 }
72 }
73
74 func TestBrandNameZero(t *testing.T) {
75 if len(cpu.brandname) > 0 {
76 // Cut out last byte
77 last := []byte(cpu.brandname[len(cpu.brandname)-1:])
78 if last[0] == 0 {
79 t.Fatal("last byte was zero")
80 } else if last[0] == 32 {
81 t.Fatal("whitespace wasn't trimmed")
82 }
83 }
84 }
85
86 // Generated here: http://play.golang.org/p/mko-0tFt0Q
87
88 // TestCmov tests Cmov() function
89 func TestCmov(t *testing.T) {
90 got := cpu.cmov()
91 expected := cpu.features&cmov == cmov
92 if got != expected {
93 t.Fatalf("Cmov: expected %v, got %v", expected, got)
94 }
95 t.Log("CMOV Support:", got)
96 }
97
98 // TestAmd3dnow tests Amd3dnow() function
99 func TestAmd3dnow(t *testing.T) {
100 got := cpu.amd3dnow()
101 expected := cpu.features&amd3dnow == amd3dnow
102 if got != expected {
103 t.Fatalf("Amd3dnow: expected %v, got %v", expected, got)
104 }
105 t.Log("AMD3DNOW Support:", got)
106 }
107
108 // TestAmd3dnowExt tests Amd3dnowExt() function
109 func TestAmd3dnowExt(t *testing.T) {
110 got := cpu.amd3dnowext()
111 expected := cpu.features&amd3dnowext == amd3dnowext
112 if got != expected {
113 t.Fatalf("Amd3dnowExt: expected %v, got %v", expected, got)
114 }
115 t.Log("AMD3DNOWEXT Support:", got)
116 }
117
118 // TestMMX tests MMX() function
119 func TestMMX(t *testing.T) {
120 got := cpu.mmx()
121 expected := cpu.features&mmx == mmx
122 if got != expected {
123 t.Fatalf("MMX: expected %v, got %v", expected, got)
124 }
125 t.Log("MMX Support:", got)
126 }
127
128 // TestMMXext tests MMXext() function
129 func TestMMXext(t *testing.T) {
130 got := cpu.mmxext()
131 expected := cpu.features&mmxext == mmxext
132 if got != expected {
133 t.Fatalf("MMXExt: expected %v, got %v", expected, got)
134 }
135 t.Log("MMXEXT Support:", got)
136 }
137
138 // TestSSE tests SSE() function
139 func TestSSE(t *testing.T) {
140 got := cpu.sse()
141 expected := cpu.features&sse == sse
142 if got != expected {
143 t.Fatalf("SSE: expected %v, got %v", expected, got)
144 }
145 t.Log("SSE Support:", got)
146 }
147
148 // TestSSE2 tests SSE2() function
149 func TestSSE2(t *testing.T) {
150 got := cpu.sse2()
151 expected := cpu.features&sse2 == sse2
152 if got != expected {
153 t.Fatalf("SSE2: expected %v, got %v", expected, got)
154 }
155 t.Log("SSE2 Support:", got)
156 }
157
158 // TestSSE3 tests SSE3() function
159 func TestSSE3(t *testing.T) {
160 got := cpu.sse3()
161 expected := cpu.features&sse3 == sse3
162 if got != expected {
163 t.Fatalf("SSE3: expected %v, got %v", expected, got)
164 }
165 t.Log("SSE3 Support:", got)
166 }
167
168 // TestSSSE3 tests SSSE3() function
169 func TestSSSE3(t *testing.T) {
170 got := cpu.ssse3()
171 expected := cpu.features&ssse3 == ssse3
172 if got != expected {
173 t.Fatalf("SSSE3: expected %v, got %v", expected, got)
174 }
175 t.Log("SSSE3 Support:", got)
176 }
177
178 // TestSSE4 tests SSE4() function
179 func TestSSE4(t *testing.T) {
180 got := cpu.sse4()
181 expected := cpu.features&sse4 == sse4
182 if got != expected {
183 t.Fatalf("SSE4: expected %v, got %v", expected, got)
184 }
185 t.Log("SSE4 Support:", got)
186 }
187
188 // TestSSE42 tests SSE42() function
189 func TestSSE42(t *testing.T) {
190 got := cpu.sse42()
191 expected := cpu.features&sse42 == sse42
192 if got != expected {
193 t.Fatalf("SSE42: expected %v, got %v", expected, got)
194 }
195 t.Log("SSE42 Support:", got)
196 }
197
198 // TestAVX tests AVX() function
199 func TestAVX(t *testing.T) {
200 got := cpu.avx()
201 expected := cpu.features&avx == avx
202 if got != expected {
203 t.Fatalf("AVX: expected %v, got %v", expected, got)
204 }
205 t.Log("AVX Support:", got)
206 }
207
208 // TestAVX2 tests AVX2() function
209 func TestAVX2(t *testing.T) {
210 got := cpu.avx2()
211 expected := cpu.features&avx2 == avx2
212 if got != expected {
213 t.Fatalf("AVX2: expected %v, got %v", expected, got)
214 }
215 t.Log("AVX2 Support:", got)
216 }
217
218 // TestFMA3 tests FMA3() function
219 func TestFMA3(t *testing.T) {
220 got := cpu.fma3()
221 expected := cpu.features&fma3 == fma3
222 if got != expected {
223 t.Fatalf("FMA3: expected %v, got %v", expected, got)
224 }
225 t.Log("FMA3 Support:", got)
226 }
227
228 // TestFMA4 tests FMA4() function
229 func TestFMA4(t *testing.T) {
230 got := cpu.fma4()
231 expected := cpu.features&fma4 == fma4
232 if got != expected {
233 t.Fatalf("FMA4: expected %v, got %v", expected, got)
234 }
235 t.Log("FMA4 Support:", got)
236 }
237
238 // TestXOP tests XOP() function
239 func TestXOP(t *testing.T) {
240 got := cpu.xop()
241 expected := cpu.features&xop == xop
242 if got != expected {
243 t.Fatalf("XOP: expected %v, got %v", expected, got)
244 }
245 t.Log("XOP Support:", got)
246 }
247
248 // TestF16C tests F16C() function
249 func TestF16C(t *testing.T) {
250 got := cpu.f16c()
251 expected := cpu.features&f16c == f16c
252 if got != expected {
253 t.Fatalf("F16C: expected %v, got %v", expected, got)
254 }
255 t.Log("F16C Support:", got)
256 }
257
258 // TestCX16 tests CX16() function
259 func TestCX16(t *testing.T) {
260 got := cpu.cx16()
261 expected := cpu.features&cx16 == cx16
262 if got != expected {
263 t.Fatalf("CX16: expected %v, got %v", expected, got)
264 }
265 t.Log("CX16 Support:", got)
266 }
267
268 // TestBMI1 tests BMI1() function
269 func TestBMI1(t *testing.T) {
270 got := cpu.bmi1()
271 expected := cpu.features&bmi1 == bmi1
272 if got != expected {
273 t.Fatalf("BMI1: expected %v, got %v", expected, got)
274 }
275 t.Log("BMI1 Support:", got)
276 }
277
278 // TestBMI2 tests BMI2() function
279 func TestBMI2(t *testing.T) {
280 got := cpu.bmi2()
281 expected := cpu.features&bmi2 == bmi2
282 if got != expected {
283 t.Fatalf("BMI2: expected %v, got %v", expected, got)
284 }
285 t.Log("BMI2 Support:", got)
286 }
287
288 // TestTBM tests TBM() function
289 func TestTBM(t *testing.T) {
290 got := cpu.tbm()
291 expected := cpu.features&tbm == tbm
292 if got != expected {
293 t.Fatalf("TBM: expected %v, got %v", expected, got)
294 }
295 t.Log("TBM Support:", got)
296 }
297
298 // TestLzcnt tests Lzcnt() function
299 func TestLzcnt(t *testing.T) {
300 got := cpu.lzcnt()
301 expected := cpu.features&lzcnt == lzcnt
302 if got != expected {
303 t.Fatalf("Lzcnt: expected %v, got %v", expected, got)
304 }
305 t.Log("LZCNT Support:", got)
306 }
307
308 // TestLzcnt tests Lzcnt() function
309 func TestPopcnt(t *testing.T) {
310 got := cpu.popcnt()
311 expected := cpu.features&popcnt == popcnt
312 if got != expected {
313 t.Fatalf("Popcnt: expected %v, got %v", expected, got)
314 }
315 t.Log("POPCNT Support:", got)
316 }
317
318 // TestAesNi tests AesNi() function
319 func TestAesNi(t *testing.T) {
320 got := cpu.aesni()
321 expected := cpu.features&aesni == aesni
322 if got != expected {
323 t.Fatalf("AesNi: expected %v, got %v", expected, got)
324 }
325 t.Log("AESNI Support:", got)
326 }
327
328 // TestHTT tests HTT() function
329 func TestHTT(t *testing.T) {
330 got := cpu.htt()
331 expected := cpu.features&htt == htt
332 if got != expected {
333 t.Fatalf("HTT: expected %v, got %v", expected, got)
334 }
335 t.Log("HTT Support:", got)
336 }
337
338 // TestClmul tests Clmul() function
339 func TestClmul(t *testing.T) {
340 got := cpu.clmul()
341 expected := cpu.features&clmul == clmul
342 if got != expected {
343 t.Fatalf("Clmul: expected %v, got %v", expected, got)
344 }
345 t.Log("CLMUL Support:", got)
346 }
347
348 // TestSSE2Slow tests SSE2Slow() function
349 func TestSSE2Slow(t *testing.T) {
350 got := cpu.sse2slow()
351 expected := cpu.features&sse2slow == sse2slow
352 if got != expected {
353 t.Fatalf("SSE2Slow: expected %v, got %v", expected, got)
354 }
355 t.Log("SSE2SLOW Support:", got)
356 }
357
358 // TestSSE3Slow tests SSE3slow() function
359 func TestSSE3Slow(t *testing.T) {
360 got := cpu.sse3slow()
361 expected := cpu.features&sse3slow == sse3slow
362 if got != expected {
363 t.Fatalf("SSE3slow: expected %v, got %v", expected, got)
364 }
365 t.Log("SSE3SLOW Support:", got)
366 }
367
368 // TestAtom tests Atom() function
369 func TestAtom(t *testing.T) {
370 got := cpu.atom()
371 expected := cpu.features&atom == atom
372 if got != expected {
373 t.Fatalf("Atom: expected %v, got %v", expected, got)
374 }
375 t.Log("ATOM Support:", got)
376 }
377
378 // TestNX tests NX() function (NX (No-Execute) bit)
379 func TestNX(t *testing.T) {
380 got := cpu.nx()
381 expected := cpu.features&nx == nx
382 if got != expected {
383 t.Fatalf("NX: expected %v, got %v", expected, got)
384 }
385 t.Log("NX Support:", got)
386 }
387
388 // TestSSE4A tests SSE4A() function (AMD Barcelona microarchitecture SSE4a instructions)
389 func TestSSE4A(t *testing.T) {
390 got := cpu.sse4a()
391 expected := cpu.features&sse4a == sse4a
392 if got != expected {
393 t.Fatalf("SSE4A: expected %v, got %v", expected, got)
394 }
395 t.Log("SSE4A Support:", got)
396 }
397
398 // TestHLE tests HLE() function (Hardware Lock Elision)
399 func TestHLE(t *testing.T) {
400 got := cpu.hle()
401 expected := cpu.features&hle == hle
402 if got != expected {
403 t.Fatalf("HLE: expected %v, got %v", expected, got)
404 }
405 t.Log("HLE Support:", got)
406 }
407
408 // TestRTM tests RTM() function (Restricted Transactional Memory)
409 func TestRTM(t *testing.T) {
410 got := cpu.rtm()
411 expected := cpu.features&rtm == rtm
412 if got != expected {
413 t.Fatalf("RTM: expected %v, got %v", expected, got)
414 }
415 t.Log("RTM Support:", got)
416 }
417
418 // TestRdrand tests RDRAND() function (RDRAND instruction is available)
419 func TestRdrand(t *testing.T) {
420 got := cpu.rdrand()
421 expected := cpu.features&rdrand == rdrand
422 if got != expected {
423 t.Fatalf("Rdrand: expected %v, got %v", expected, got)
424 }
425 t.Log("Rdrand Support:", got)
426 }
427
428 // TestRdseed tests RDSEED() function (RDSEED instruction is available)
429 func TestRdseed(t *testing.T) {
430 got := cpu.rdseed()
431 expected := cpu.features&rdseed == rdseed
432 if got != expected {
433 t.Fatalf("Rdseed: expected %v, got %v", expected, got)
434 }
435 t.Log("Rdseed Support:", got)
436 }
437
438 // TestADX tests ADX() function (Intel ADX (Multi-Precision Add-Carry Instruction Extensions))
439 func TestADX(t *testing.T) {
440 got := cpu.adx()
441 expected := cpu.features&adx == adx
442 if got != expected {
443 t.Fatalf("ADX: expected %v, got %v", expected, got)
444 }
445 t.Log("ADX Support:", got)
446 }
447
448 // TestSHA tests SHA() function (Intel SHA Extensions)
449 func TestSHA(t *testing.T) {
450 got := cpu.sha()
451 expected := cpu.features&sha == sha
452 if got != expected {
453 t.Fatalf("SHA: expected %v, got %v", expected, got)
454 }
455 t.Log("SHA Support:", got)
456 }
457
458 // TestAVX512F tests AVX512F() function (AVX-512 Foundation)
459 func TestAVX512F(t *testing.T) {
460 got := cpu.avx512f()
461 expected := cpu.features&avx512f == avx512f
462 if got != expected {
463 t.Fatalf("AVX512F: expected %v, got %v", expected, got)
464 }
465 t.Log("AVX512F Support:", got)
466 }
467
468 // TestAVX512DQ tests AVX512DQ() function (AVX-512 Doubleword and Quadword Instructions)
469 func TestAVX512DQ(t *testing.T) {
470 got := cpu.avx512dq()
471 expected := cpu.features&avx512dq == avx512dq
472 if got != expected {
473 t.Fatalf("AVX512DQ: expected %v, got %v", expected, got)
474 }
475 t.Log("AVX512DQ Support:", got)
476 }
477
478 // TestAVX512IFMA tests AVX512IFMA() function (AVX-512 Integer Fused Multiply-Add Instructions)
479 func TestAVX512IFMA(t *testing.T) {
480 got := cpu.avx512ifma()
481 expected := cpu.features&avx512ifma == avx512ifma
482 if got != expected {
483 t.Fatalf("AVX512IFMA: expected %v, got %v", expected, got)
484 }
485 t.Log("AVX512IFMA Support:", got)
486 }
487
488 // TestAVX512PF tests AVX512PF() function (AVX-512 Prefetch Instructions)
489 func TestAVX512PF(t *testing.T) {
490 got := cpu.avx512pf()
491 expected := cpu.features&avx512pf == avx512pf
492 if got != expected {
493 t.Fatalf("AVX512PF: expected %v, got %v", expected, got)
494 }
495 t.Log("AVX512PF Support:", got)
496 }
497
498 // TestAVX512ER tests AVX512ER() function (AVX-512 Exponential and Reciprocal Instructions)
499 func TestAVX512ER(t *testing.T) {
500 got := cpu.avx512er()
501 expected := cpu.features&avx512er == avx512er
502 if got != expected {
503 t.Fatalf("AVX512ER: expected %v, got %v", expected, got)
504 }
505 t.Log("AVX512ER Support:", got)
506 }
507
508 // TestAVX512CD tests AVX512CD() function (AVX-512 Conflict Detection Instructions)
509 func TestAVX512CD(t *testing.T) {
510 got := cpu.avx512cd()
511 expected := cpu.features&avx512cd == avx512cd
512 if got != expected {
513 t.Fatalf("AVX512CD: expected %v, got %v", expected, got)
514 }
515 t.Log("AVX512CD Support:", got)
516 }
517
518 // TestAVX512BW tests AVX512BW() function (AVX-512 Byte and Word Instructions)
519 func TestAVX512BW(t *testing.T) {
520 got := cpu.avx512bw()
521 expected := cpu.features&avx512bw == avx512bw
522 if got != expected {
523 t.Fatalf("AVX512BW: expected %v, got %v", expected, got)
524 }
525 t.Log("AVX512BW Support:", got)
526 }
527
528 // TestAVX512VL tests AVX512VL() function (AVX-512 Vector Length Extensions)
529 func TestAVX512VL(t *testing.T) {
530 got := cpu.avx512vl()
531 expected := cpu.features&avx512vl == avx512vl
532 if got != expected {
533 t.Fatalf("AVX512VL: expected %v, got %v", expected, got)
534 }
535 t.Log("AVX512VL Support:", got)
536 }
537
538 // TestAVX512VL tests AVX512VBMI() function (AVX-512 Vector Bit Manipulation Instructions)
539 func TestAVX512VBMI(t *testing.T) {
540 got := cpu.avx512vbmi()
541 expected := cpu.features&avx512vbmi == avx512vbmi
542 if got != expected {
543 t.Fatalf("AVX512VBMI: expected %v, got %v", expected, got)
544 }
545 t.Log("AVX512VBMI Support:", got)
546 }
547
548 // TestMPX tests MPX() function (Intel MPX (Memory Protection Extensions))
549 func TestMPX(t *testing.T) {
550 got := cpu.mpx()
551 expected := cpu.features&mpx == mpx
552 if got != expected {
553 t.Fatalf("MPX: expected %v, got %v", expected, got)
554 }
555 t.Log("MPX Support:", got)
556 }
557
558 // TestERMS tests ERMS() function (Enhanced REP MOVSB/STOSB)
559 func TestERMS(t *testing.T) {
560 got := cpu.erms()
561 expected := cpu.features&erms == erms
562 if got != expected {
563 t.Fatalf("ERMS: expected %v, got %v", expected, got)
564 }
565 t.Log("ERMS Support:", got)
566 }
567
568 // TestVendor writes the detected vendor. Will be 0 if unknown
569 func TestVendor(t *testing.T) {
570 t.Log("Vendor ID:", cpu.vendorid)
571 }
572
573 // Intel returns true if vendor is recognized as Intel
574 func TestIntel(t *testing.T) {
575 got := cpu.intel()
576 expected := cpu.vendorid == intel
577 if got != expected {
578 t.Fatalf("TestIntel: expected %v, got %v", expected, got)
579 }
580 t.Log("TestIntel:", got)
581 }
582
583 // AMD returns true if vendor is recognized as AMD
584 func TestAMD(t *testing.T) {
585 got := cpu.amd()
586 expected := cpu.vendorid == amd
587 if got != expected {
588 t.Fatalf("TestAMD: expected %v, got %v", expected, got)
589 }
590 t.Log("TestAMD:", got)
591 }
592
593 // Transmeta returns true if vendor is recognized as Transmeta
594 func TestTransmeta(t *testing.T) {
595 got := cpu.transmeta()
596 expected := cpu.vendorid == transmeta
597 if got != expected {
598 t.Fatalf("TestTransmeta: expected %v, got %v", expected, got)
599 }
600 t.Log("TestTransmeta:", got)
601 }
602
603 // NSC returns true if vendor is recognized as National Semiconductor
604 func TestNSC(t *testing.T) {
605 got := cpu.nsc()
606 expected := cpu.vendorid == nsc
607 if got != expected {
608 t.Fatalf("TestNSC: expected %v, got %v", expected, got)
609 }
610 t.Log("TestNSC:", got)
611 }
612
613 // VIA returns true if vendor is recognized as VIA
614 func TestVIA(t *testing.T) {
615 got := cpu.via()
616 expected := cpu.vendorid == via
617 if got != expected {
618 t.Fatalf("TestVIA: expected %v, got %v", expected, got)
619 }
620 t.Log("TestVIA:", got)
621 }
622
623 // Test VM function
624 func TestVM(t *testing.T) {
625 t.Log("Vendor ID:", cpu.vm())
626 }
627
628 // Test RTCounter function
629 func TestRtCounter(t *testing.T) {
630 a := cpu.rtcounter()
631 b := cpu.rtcounter()
632 t.Log("CPU Counter:", a, b, b-a)
633 }
634
635 // Prints the value of Ia32TscAux()
636 func TestIa32TscAux(t *testing.T) {
637 ecx := cpu.ia32tscaux()
638 t.Logf("Ia32TscAux:0x%x\n", ecx)
639 if ecx != 0 {
640 chip := (ecx & 0xFFF000) >> 12
641 core := ecx & 0xFFF
642 t.Log("Likely chip, core:", chip, core)
643 }
644 }
645
646 func TestThreadsPerCoreNZ(t *testing.T) {
647 if cpu.threadspercore == 0 {
648 t.Fatal("threads per core is zero")
649 }
650 }
651
652 // Prints the value of LogicalCPU()
653 func TestLogicalCPU(t *testing.T) {
654 t.Log("Currently executing on cpu:", cpu.logicalcpu())
655 }
656
657 func TestMaxFunction(t *testing.T) {
658 expect := maxFunctionID()
659 if cpu.maxFunc != expect {
660 t.Fatal("Max function does not match, expected", expect, "but got", cpu.maxFunc)
661 }
662 expect = maxExtendedFunction()
663 if cpu.maxExFunc != expect {
664 t.Fatal("Max Extended function does not match, expected", expect, "but got", cpu.maxFunc)
665 }
666 }
667
668 // This example will calculate the chip/core number on Linux
669 // Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX.
670 func examplecpuinfo_ia32tscaux(t *testing.T) {
671 ecx := cpu.ia32tscaux()
672 if ecx == 0 {
673 fmt.Println("Unknown CPU ID")
674 return
675 }
676 chip := (ecx & 0xFFF000) >> 12
677 core := ecx & 0xFFF
678 fmt.Println("Chip, Core:", chip, core)
679 }
680
681 /*
682 func TestPhysical(t *testing.T) {
683 var test16 = "CPUID 00000000: 0000000d-756e6547-6c65746e-49656e69 \nCPUID 00000001: 000206d7-03200800-1fbee3ff-bfebfbff \nCPUID 00000002: 76035a01-00f0b2ff-00000000-00ca0000 \nCPUID 00000003: 00000000-00000000-00000000-00000000 \nCPUID 00000004: 3c004121-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004122-01c0003f-0000003f-00000000 \nCPUID 00000004: 3c004143-01c0003f-000001ff-00000000 \nCPUID 00000004: 3c07c163-04c0003f-00003fff-00000006 \nCPUID 00000005: 00000040-00000040-00000003-00021120 \nCPUID 00000006: 00000075-00000002-00000009-00000000 \nCPUID 00000007: 00000000-00000000-00000000-00000000 \nCPUID 00000008: 00000000-00000000-00000000-00000000 \nCPUID 00000009: 00000001-00000000-00000000-00000000 \nCPUID 0000000a: 07300403-00000000-00000000-00000603 \nCPUID 0000000b: 00000000-00000000-00000003-00000003 \nCPUID 0000000b: 00000005-00000010-00000201-00000003 \nCPUID 0000000c: 00000000-00000000-00000000-00000000 \nCPUID 0000000d: 00000007-00000340-00000340-00000000 \nCPUID 0000000d: 00000001-00000000-00000000-00000000 \nCPUID 0000000d: 00000100-00000240-00000000-00000000 \nCPUID 80000000: 80000008-00000000-00000000-00000000 \nCPUID 80000001: 00000000-00000000-00000001-2c100800 \nCPUID 80000002: 20202020-49202020-6c65746e-20295228 \nCPUID 80000003: 6e6f6558-20295228-20555043-322d3545 \nCPUID 80000004: 20303636-20402030-30322e32-007a4847 \nCPUID 80000005: 00000000-00000000-00000000-00000000 \nCPUID 80000006: 00000000-00000000-01006040-00000000 \nCPUID 80000007: 00000000-00000000-00000000-00000100 \nCPUID 80000008: 0000302e-00000000-00000000-00000000"
684 restore := mockCPU([]byte(test16))
685 Detect()
686 t.Log("Name:", CPU.BrandName)
687 n := maxFunctionID()
688 t.Logf("Max Function:0x%x\n", n)
689 n = maxExtendedFunction()
690 t.Logf("Max Extended Function:0x%x\n", n)
691 t.Log("PhysicalCores:", CPU.PhysicalCores)
692 t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
693 t.Log("LogicalCores:", CPU.LogicalCores)
694 t.Log("Family", CPU.Family, "Model:", CPU.Model)
695 t.Log("Features:", CPU.Features)
696 t.Log("Cacheline bytes:", CPU.CacheLine)
697 t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
698 t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
699 t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
700 t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
701 if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 {
702 if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore {
703 t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)",
704 CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore)
705 }
706 }
707
708 if CPU.ThreadsPerCore > 1 && !CPU.HTT() {
709 t.Fatalf("Hyperthreading not detected")
710 }
711 if CPU.ThreadsPerCore == 1 && CPU.HTT() {
712 t.Fatalf("Hyperthreading detected, but only 1 Thread per core")
713 }
714 restore()
715 Detect()
716 TestCPUID(t)
717 }
718 */
0 // +build ignore
1
2 package main
3
4 import (
5 "bytes"
6 "fmt"
7 "go/ast"
8 "go/parser"
9 "go/printer"
10 "go/token"
11 "io"
12 "io/ioutil"
13 "log"
14 "os"
15 "reflect"
16 "strings"
17 "unicode"
18 "unicode/utf8"
19 )
20
21 var inFiles = []string{"cpuid.go", "cpuid_test.go"}
22 var copyFiles = []string{"cpuid_amd64.s", "cpuid_386.s", "detect_ref.go", "detect_intel.go"}
23 var fileSet = token.NewFileSet()
24 var reWrites = []rewrite{
25 initRewrite("CPUInfo -> cpuInfo"),
26 initRewrite("Vendor -> vendor"),
27 initRewrite("Flags -> flags"),
28 initRewrite("Detect -> detect"),
29 initRewrite("CPU -> cpu"),
30 }
31 var excludeNames = map[string]bool{"string": true, "join": true, "trim": true,
32 // cpuid_test.go
33 "t": true, "println": true, "logf": true, "log": true, "fatalf": true, "fatal": true,
34 }
35
36 var excludePrefixes = []string{"test", "benchmark"}
37
38 func main() {
39 Package := "private"
40 parserMode := parser.ParseComments
41 exported := make(map[string]rewrite)
42 for _, file := range inFiles {
43 in, err := os.Open(file)
44 if err != nil {
45 log.Fatalf("opening input", err)
46 }
47
48 src, err := ioutil.ReadAll(in)
49 if err != nil {
50 log.Fatalf("reading input", err)
51 }
52
53 astfile, err := parser.ParseFile(fileSet, file, src, parserMode)
54 if err != nil {
55 log.Fatalf("parsing input", err)
56 }
57
58 for _, rw := range reWrites {
59 astfile = rw(astfile)
60 }
61
62 // Inspect the AST and print all identifiers and literals.
63 var startDecl token.Pos
64 var endDecl token.Pos
65 ast.Inspect(astfile, func(n ast.Node) bool {
66 var s string
67 switch x := n.(type) {
68 case *ast.Ident:
69 if x.IsExported() {
70 t := strings.ToLower(x.Name)
71 for _, pre := range excludePrefixes {
72 if strings.HasPrefix(t, pre) {
73 return true
74 }
75 }
76 if excludeNames[t] != true {
77 //if x.Pos() > startDecl && x.Pos() < endDecl {
78 exported[x.Name] = initRewrite(x.Name + " -> " + t)
79 }
80 }
81
82 case *ast.GenDecl:
83 if x.Tok == token.CONST && x.Lparen > 0 {
84 startDecl = x.Lparen
85 endDecl = x.Rparen
86 // fmt.Printf("Decl:%s -> %s\n", fileSet.Position(startDecl), fileSet.Position(endDecl))
87 }
88 }
89 if s != "" {
90 fmt.Printf("%s:\t%s\n", fileSet.Position(n.Pos()), s)
91 }
92 return true
93 })
94
95 for _, rw := range exported {
96 astfile = rw(astfile)
97 }
98
99 var buf bytes.Buffer
100
101 printer.Fprint(&buf, fileSet, astfile)
102
103 // Remove package documentation and insert information
104 s := buf.String()
105 ind := strings.Index(buf.String(), "\npackage cpuid")
106 s = s[ind:]
107 s = "// Generated, DO NOT EDIT,\n" +
108 "// but copy it to your own project and rename the package.\n" +
109 "// See more at http://github.com/klauspost/cpuid\n" +
110 s
111
112 outputName := Package + string(os.PathSeparator) + file
113
114 err = ioutil.WriteFile(outputName, []byte(s), 0644)
115 if err != nil {
116 log.Fatalf("writing output: %s", err)
117 }
118 log.Println("Generated", outputName)
119 }
120
121 for _, file := range copyFiles {
122 dst := ""
123 if strings.HasPrefix(file, "cpuid") {
124 dst = Package + string(os.PathSeparator) + file
125 } else {
126 dst = Package + string(os.PathSeparator) + "cpuid_" + file
127 }
128 err := copyFile(file, dst)
129 if err != nil {
130 log.Fatalf("copying file: %s", err)
131 }
132 log.Println("Copied", dst)
133 }
134 }
135
136 // CopyFile copies a file from src to dst. If src and dst files exist, and are
137 // the same, then return success. Copy the file contents from src to dst.
138 func copyFile(src, dst string) (err error) {
139 sfi, err := os.Stat(src)
140 if err != nil {
141 return
142 }
143 if !sfi.Mode().IsRegular() {
144 // cannot copy non-regular files (e.g., directories,
145 // symlinks, devices, etc.)
146 return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
147 }
148 dfi, err := os.Stat(dst)
149 if err != nil {
150 if !os.IsNotExist(err) {
151 return
152 }
153 } else {
154 if !(dfi.Mode().IsRegular()) {
155 return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
156 }
157 if os.SameFile(sfi, dfi) {
158 return
159 }
160 }
161 err = copyFileContents(src, dst)
162 return
163 }
164
165 // copyFileContents copies the contents of the file named src to the file named
166 // by dst. The file will be created if it does not already exist. If the
167 // destination file exists, all it's contents will be replaced by the contents
168 // of the source file.
169 func copyFileContents(src, dst string) (err error) {
170 in, err := os.Open(src)
171 if err != nil {
172 return
173 }
174 defer in.Close()
175 out, err := os.Create(dst)
176 if err != nil {
177 return
178 }
179 defer func() {
180 cerr := out.Close()
181 if err == nil {
182 err = cerr
183 }
184 }()
185 if _, err = io.Copy(out, in); err != nil {
186 return
187 }
188 err = out.Sync()
189 return
190 }
191
192 type rewrite func(*ast.File) *ast.File
193
194 // Mostly copied from gofmt
195 func initRewrite(rewriteRule string) rewrite {
196 f := strings.Split(rewriteRule, "->")
197 if len(f) != 2 {
198 fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
199 os.Exit(2)
200 }
201 pattern := parseExpr(f[0], "pattern")
202 replace := parseExpr(f[1], "replacement")
203 return func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
204 }
205
206 // parseExpr parses s as an expression.
207 // It might make sense to expand this to allow statement patterns,
208 // but there are problems with preserving formatting and also
209 // with what a wildcard for a statement looks like.
210 func parseExpr(s, what string) ast.Expr {
211 x, err := parser.ParseExpr(s)
212 if err != nil {
213 fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
214 os.Exit(2)
215 }
216 return x
217 }
218
219 // Keep this function for debugging.
220 /*
221 func dump(msg string, val reflect.Value) {
222 fmt.Printf("%s:\n", msg)
223 ast.Print(fileSet, val.Interface())
224 fmt.Println()
225 }
226 */
227
228 // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
229 func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
230 cmap := ast.NewCommentMap(fileSet, p, p.Comments)
231 m := make(map[string]reflect.Value)
232 pat := reflect.ValueOf(pattern)
233 repl := reflect.ValueOf(replace)
234
235 var rewriteVal func(val reflect.Value) reflect.Value
236 rewriteVal = func(val reflect.Value) reflect.Value {
237 // don't bother if val is invalid to start with
238 if !val.IsValid() {
239 return reflect.Value{}
240 }
241 for k := range m {
242 delete(m, k)
243 }
244 val = apply(rewriteVal, val)
245 if match(m, pat, val) {
246 val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
247 }
248 return val
249 }
250
251 r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
252 r.Comments = cmap.Filter(r).Comments() // recreate comments list
253 return r
254 }
255
256 // set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
257 func set(x, y reflect.Value) {
258 // don't bother if x cannot be set or y is invalid
259 if !x.CanSet() || !y.IsValid() {
260 return
261 }
262 defer func() {
263 if x := recover(); x != nil {
264 if s, ok := x.(string); ok &&
265 (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
266 // x cannot be set to y - ignore this rewrite
267 return
268 }
269 panic(x)
270 }
271 }()
272 x.Set(y)
273 }
274
275 // Values/types for special cases.
276 var (
277 objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
278 scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
279
280 identType = reflect.TypeOf((*ast.Ident)(nil))
281 objectPtrType = reflect.TypeOf((*ast.Object)(nil))
282 positionType = reflect.TypeOf(token.NoPos)
283 callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
284 scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
285 )
286
287 // apply replaces each AST field x in val with f(x), returning val.
288 // To avoid extra conversions, f operates on the reflect.Value form.
289 func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
290 if !val.IsValid() {
291 return reflect.Value{}
292 }
293
294 // *ast.Objects introduce cycles and are likely incorrect after
295 // rewrite; don't follow them but replace with nil instead
296 if val.Type() == objectPtrType {
297 return objectPtrNil
298 }
299
300 // similarly for scopes: they are likely incorrect after a rewrite;
301 // replace them with nil
302 if val.Type() == scopePtrType {
303 return scopePtrNil
304 }
305
306 switch v := reflect.Indirect(val); v.Kind() {
307 case reflect.Slice:
308 for i := 0; i < v.Len(); i++ {
309 e := v.Index(i)
310 set(e, f(e))
311 }
312 case reflect.Struct:
313 for i := 0; i < v.NumField(); i++ {
314 e := v.Field(i)
315 set(e, f(e))
316 }
317 case reflect.Interface:
318 e := v.Elem()
319 set(v, f(e))
320 }
321 return val
322 }
323
324 func isWildcard(s string) bool {
325 rune, size := utf8.DecodeRuneInString(s)
326 return size == len(s) && unicode.IsLower(rune)
327 }
328
329 // match returns true if pattern matches val,
330 // recording wildcard submatches in m.
331 // If m == nil, match checks whether pattern == val.
332 func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
333 // Wildcard matches any expression. If it appears multiple
334 // times in the pattern, it must match the same expression
335 // each time.
336 if m != nil && pattern.IsValid() && pattern.Type() == identType {
337 name := pattern.Interface().(*ast.Ident).Name
338 if isWildcard(name) && val.IsValid() {
339 // wildcards only match valid (non-nil) expressions.
340 if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
341 if old, ok := m[name]; ok {
342 return match(nil, old, val)
343 }
344 m[name] = val
345 return true
346 }
347 }
348 }
349
350 // Otherwise, pattern and val must match recursively.
351 if !pattern.IsValid() || !val.IsValid() {
352 return !pattern.IsValid() && !val.IsValid()
353 }
354 if pattern.Type() != val.Type() {
355 return false
356 }
357
358 // Special cases.
359 switch pattern.Type() {
360 case identType:
361 // For identifiers, only the names need to match
362 // (and none of the other *ast.Object information).
363 // This is a common case, handle it all here instead
364 // of recursing down any further via reflection.
365 p := pattern.Interface().(*ast.Ident)
366 v := val.Interface().(*ast.Ident)
367 return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
368 case objectPtrType, positionType:
369 // object pointers and token positions always match
370 return true
371 case callExprType:
372 // For calls, the Ellipsis fields (token.Position) must
373 // match since that is how f(x) and f(x...) are different.
374 // Check them here but fall through for the remaining fields.
375 p := pattern.Interface().(*ast.CallExpr)
376 v := val.Interface().(*ast.CallExpr)
377 if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
378 return false
379 }
380 }
381
382 p := reflect.Indirect(pattern)
383 v := reflect.Indirect(val)
384 if !p.IsValid() || !v.IsValid() {
385 return !p.IsValid() && !v.IsValid()
386 }
387
388 switch p.Kind() {
389 case reflect.Slice:
390 if p.Len() != v.Len() {
391 return false
392 }
393 for i := 0; i < p.Len(); i++ {
394 if !match(m, p.Index(i), v.Index(i)) {
395 return false
396 }
397 }
398 return true
399
400 case reflect.Struct:
401 for i := 0; i < p.NumField(); i++ {
402 if !match(m, p.Field(i), v.Field(i)) {
403 return false
404 }
405 }
406 return true
407
408 case reflect.Interface:
409 return match(m, p.Elem(), v.Elem())
410 }
411
412 // Handle token integers, etc.
413 return p.Interface() == v.Interface()
414 }
415
416 // subst returns a copy of pattern with values from m substituted in place
417 // of wildcards and pos used as the position of tokens from the pattern.
418 // if m == nil, subst returns a copy of pattern and doesn't change the line
419 // number information.
420 func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
421 if !pattern.IsValid() {
422 return reflect.Value{}
423 }
424
425 // Wildcard gets replaced with map value.
426 if m != nil && pattern.Type() == identType {
427 name := pattern.Interface().(*ast.Ident).Name
428 if isWildcard(name) {
429 if old, ok := m[name]; ok {
430 return subst(nil, old, reflect.Value{})
431 }
432 }
433 }
434
435 if pos.IsValid() && pattern.Type() == positionType {
436 // use new position only if old position was valid in the first place
437 if old := pattern.Interface().(token.Pos); !old.IsValid() {
438 return pattern
439 }
440 return pos
441 }
442
443 // Otherwise copy.
444 switch p := pattern; p.Kind() {
445 case reflect.Slice:
446 v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
447 for i := 0; i < p.Len(); i++ {
448 v.Index(i).Set(subst(m, p.Index(i), pos))
449 }
450 return v
451
452 case reflect.Struct:
453 v := reflect.New(p.Type()).Elem()
454 for i := 0; i < p.NumField(); i++ {
455 v.Field(i).Set(subst(m, p.Field(i), pos))
456 }
457 return v
458
459 case reflect.Ptr:
460 v := reflect.New(p.Type()).Elem()
461 if elem := p.Elem(); elem.IsValid() {
462 v.Set(subst(m, elem, pos).Addr())
463 }
464 return v
465
466 case reflect.Interface:
467 v := reflect.New(p.Type()).Elem()
468 if elem := p.Elem(); elem.IsValid() {
469 v.Set(subst(m, elem, pos))
470 }
471 return v
472 }
473
474 return pattern
475 }
Binary diff not shown
0 package main
1
2 import (
3 "archive/zip"
4 _ "bytes"
5 "fmt"
6 "golang.org/x/net/html"
7 "io"
8 "net/http"
9 "os"
10 "strings"
11 )
12
13 // Download all CPUID dumps from http://users.atw.hu/instlatx64/
14 func main() {
15 resp, err := http.Get("http://users.atw.hu/instlatx64/?")
16 if err != nil {
17 panic(err)
18 }
19
20 node, err := html.Parse(resp.Body)
21 if err != nil {
22 panic(err)
23 }
24
25 file, err := os.Create("cpuid_data.zip")
26 if err != nil {
27 panic(err)
28 }
29 defer file.Close()
30 gw := zip.NewWriter(file)
31
32 var f func(*html.Node)
33 f = func(n *html.Node) {
34 if n.Type == html.ElementNode && n.Data == "a" {
35 for _, a := range n.Attr {
36 if a.Key == "href" {
37 err := ParseURL(a.Val, gw)
38 if err != nil {
39 panic(err)
40 }
41 break
42 }
43 }
44 }
45 for c := n.FirstChild; c != nil; c = c.NextSibling {
46 f(c)
47 }
48 }
49
50 f(node)
51 err = gw.Close()
52 if err != nil {
53 panic(err)
54 }
55 }
56
57 func ParseURL(s string, gw *zip.Writer) error {
58 if strings.Contains(s, "CPUID.txt") {
59 fmt.Println("Adding", "http://users.atw.hu/instlatx64/"+s)
60 resp, err := http.Get("http://users.atw.hu/instlatx64/" + s)
61 if err != nil {
62 fmt.Println("Error getting ", s, ":", err)
63 }
64 defer resp.Body.Close()
65 w, err := gw.Create(s)
66 if err != nil {
67 return err
68 }
69
70 _, err = io.Copy(w, resp.Body)
71 if err != nil {
72 return err
73 }
74 }
75 return nil
76 }