Imported Upstream version 0.0~git20151214.0.ef30b90
Alexandre Viau
8 years ago
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 | 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 | } |