Skip to content

Commit eb76847

Browse files
authored
Add Microarchitecture levels (#92)
From https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels Example: ``` Name: AMD Ryzen 9 3950X 16-Core Processor Vendor String: AuthenticAMD Vendor ID: AMD PhysicalCores: 16 Threads Per Core: 2 Logical Cores: 32 CPU Family 23 Model: 113 Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CLZERO,CMOV,CMPXCHG8,CPBOOST,CX16,F16C,FMA3,FXSR,FXSROPT,HTT,HYPERVISOR,LAHF,LZCNT,MCAOVERFLOW,MMX,MMXEXT,MOVBE,NX,OSXSAVE,POPCNT,RDRAND,RDSEED,RDTSCP,SCE,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3,SUCCOR,X87,XSAVE Microarchitecture level: 3 Cacheline bytes: 64 L1 Instruction Cache: 32768 bytes L1 Data Cache: 32768 bytes L2 Cache: 524288 bytes L3 Cache: 16777216 bytes ```
1 parent cffd0d4 commit eb76847

5 files changed

Lines changed: 167 additions & 91 deletions

File tree

cmd/cpuid/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func main() {
4141
fmt.Println("Logical Cores:", cpuid.CPU.LogicalCores)
4242
fmt.Println("CPU Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model)
4343
fmt.Println("Features:", strings.Join(cpuid.CPU.FeatureSet(), ","))
44+
fmt.Println("Microarchitecture level:", cpuid.CPU.X64Level())
4445
fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine)
4546
fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1I, "bytes")
4647
fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes")

cpuid.go

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,16 @@ const (
9999
CLMUL // Carry-less Multiplication
100100
CLZERO // CLZERO instruction supported
101101
CMOV // i686 CMOV
102+
CMPXCHG8 // CMPXCHG8 instruction
102103
CPBOOST // Core Performance Boost
103104
CX16 // CMPXCHG16B Instruction
104105
ENQCMD // Enqueue Command
105106
ERMS // Enhanced REP MOVSB/STOSB
106107
F16C // Half-precision floating-point conversion
107108
FMA3 // Intel FMA 3. Does not imply AVX.
108109
FMA4 // Bulldozer FMA4 functions
110+
FXSR // FXSAVE, FXRESTOR instructions, CR4 bit 9
111+
FXSROPT // FXSAVE/FXRSTOR optimizations
109112
GFNI // Galois Field New Instructions
110113
HLE // Hardware Lock Elision
111114
HTT // Hyperthreading (enabled)
@@ -123,23 +126,27 @@ const (
123126
IBSRIPINVALIDCHK // Instruction Based Sampling Feature (AMD)
124127
INT_WBINVD // WBINVD/WBNOINVD are interruptible.
125128
INVLPGB // NVLPGB and TLBSYNC instruction supported
129+
LAHF // LAHF/SAHF in long mode
126130
LZCNT // LZCNT instruction
127131
MCAOVERFLOW // MCA overflow recovery support.
128132
MCOMMIT // MCOMMIT instruction supported
129133
MMX // standard MMX
130134
MMXEXT // SSE integer functions or AMD MMX ext
135+
MOVBE // MOVBE instruction (big-endian)
131136
MOVDIR64B // Move 64 Bytes as Direct Store
132137
MOVDIRI // Move Doubleword as Direct Store
133138
MPX // Intel MPX (Memory Protection Extensions)
134139
MSRIRC // Instruction Retired Counter MSR available
135140
NX // NX (No-Execute) bit
141+
OSXSAVE // XSAVE enabled by OS
136142
POPCNT // POPCNT instruction
137143
RDPRU // RDPRU instruction supported
138144
RDRAND // RDRAND instruction is available
139145
RDSEED // RDSEED instruction is available
140146
RDTSCP // RDTSCP Instruction
141147
RTM // Restricted Transactional Memory
142148
RTM_ALWAYS_ABORT // Indicates that the loaded microcode is forcing RTM abort.
149+
SCE // SYSENTER and SYSEXIT instructions
143150
SERIALIZE // Serialize Instruction Execution
144151
SGX // Software Guard Extensions
145152
SGXLC // Software Guard Extensions Launch Control
@@ -160,7 +167,9 @@ const (
160167
VPCLMULQDQ // Carry-Less Multiplication Quadword
161168
WAITPKG // TPAUSE, UMONITOR, UMWAIT
162169
WBNOINVD // Write Back and Do Not Invalidate Cache
170+
X87 // FPU
163171
XOP // Bulldozer XOP functions
172+
XSAVE // XSAVE, XRESTOR, XSETBV, XGETBV
164173

165174
// ARM features:
166175
AESARM // AES instructions
@@ -311,6 +320,31 @@ func (c CPUInfo) Has(id FeatureID) bool {
311320
return c.featureSet.inSet(id)
312321
}
313322

323+
// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
324+
var level1Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2)
325+
var level2Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3)
326+
var level3Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE)
327+
var level4Features = flagSetWith(CMOV, CMPXCHG8, X87, FXSR, MMX, SCE, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE, AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL)
328+
329+
// X64Level returns the microarchitecture level detected on the CPU.
330+
// If features are lacking or non x64 mode, 0 is returned.
331+
// See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
332+
func (c CPUInfo) X64Level() int {
333+
if c.featureSet.hasSet(level4Features) {
334+
return 4
335+
}
336+
if c.featureSet.hasSet(level3Features) {
337+
return 3
338+
}
339+
if c.featureSet.hasSet(level2Features) {
340+
return 2
341+
}
342+
if c.featureSet.hasSet(level1Features) {
343+
return 1
344+
}
345+
return 0
346+
}
347+
314348
// Disable will disable one or several features.
315349
func (c *CPUInfo) Disable(ids ...FeatureID) bool {
316350
for _, id := range ids {
@@ -497,6 +531,24 @@ func (s *flagSet) or(other flagSet) {
497531
}
498532
}
499533

534+
// hasSet returns whether all features are present.
535+
func (s flagSet) hasSet(other flagSet) bool {
536+
for i, v := range other[:] {
537+
if s[i]&v != v {
538+
return false
539+
}
540+
}
541+
return true
542+
}
543+
544+
func flagSetWith(feat ...FeatureID) flagSet {
545+
var res flagSet
546+
for _, f := range feat {
547+
res.set(f)
548+
}
549+
return res
550+
}
551+
500552
// ParseFeature will parse the string and return the ID of the matching feature.
501553
// Will return UNKNOWN if not found.
502554
func ParseFeature(s string) FeatureID {
@@ -706,6 +758,7 @@ func (c *CPUInfo) cacheSize() {
706758
if maxFunctionID() < 4 {
707759
return
708760
}
761+
c.Cache.L1I, c.Cache.L1D, c.Cache.L2, c.Cache.L3 = 0, 0, 0, 0
709762
for i := uint32(0); ; i++ {
710763
eax, ebx, ecx, _ := cpuidex(4, i)
711764
cacheType := eax & 15
@@ -861,9 +914,14 @@ func support() flagSet {
861914
family, model := familyModel()
862915

863916
_, _, c, d := cpuid(1)
917+
fs.setIf((d&(1<<0)) != 0, X87)
918+
fs.setIf((d&(1<<8)) != 0, CMPXCHG8)
919+
fs.setIf((d&(1<<11)) != 0, SCE)
864920
fs.setIf((d&(1<<15)) != 0, CMOV)
921+
fs.setIf((d&(1<<22)) != 0, MMXEXT)
865922
fs.setIf((d&(1<<23)) != 0, MMX)
866-
fs.setIf((d&(1<<25)) != 0, MMXEXT)
923+
fs.setIf((d&(1<<24)) != 0, FXSR)
924+
fs.setIf((d&(1<<25)) != 0, FXSROPT)
867925
fs.setIf((d&(1<<25)) != 0, SSE)
868926
fs.setIf((d&(1<<26)) != 0, SSE2)
869927
fs.setIf((c&1) != 0, SSE3)
@@ -873,6 +931,7 @@ func support() flagSet {
873931
fs.setIf((c&0x00100000) != 0, SSE42)
874932
fs.setIf((c&(1<<25)) != 0, AESNI)
875933
fs.setIf((c&(1<<1)) != 0, CLMUL)
934+
fs.setIf(c&(1<<22) != 0, MOVBE)
876935
fs.setIf(c&(1<<23) != 0, POPCNT)
877936
fs.setIf(c&(1<<30) != 0, RDRAND)
878937

@@ -888,6 +947,8 @@ func support() flagSet {
888947
if vend == AMD && (d&(1<<28)) != 0 && mfi >= 4 {
889948
fs.setIf(threadsPerCore() > 1, HTT)
890949
}
950+
fs.setIf(c&1<<26 != 0, XSAVE)
951+
fs.setIf(c&1<<27 != 0, OSXSAVE)
891952
// Check XGETBV/XSAVE (26), OXSAVE (27) and AVX (28) bits
892953
const avxCheck = 1<<26 | 1<<27 | 1<<28
893954
if c&avxCheck == avxCheck {
@@ -992,6 +1053,7 @@ func support() flagSet {
9921053
fs.set(LZCNT)
9931054
fs.set(POPCNT)
9941055
}
1056+
fs.setIf((c&(1<<0)) != 0, LAHF)
9951057
fs.setIf((c&(1<<10)) != 0, IBS)
9961058
fs.setIf((d&(1<<31)) != 0, AMD3DNOW)
9971059
fs.setIf((d&(1<<30)) != 0, AMD3DNOWEXT)

featureid_string.go

Lines changed: 98 additions & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mockcpu_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ func TestMocks(t *testing.T) {
187187
t.Log("LogicalCores:", CPU.LogicalCores)
188188
t.Log("Family", CPU.Family, "Model:", CPU.Model)
189189
t.Log("Features:", strings.Join(CPU.FeatureSet(), ","))
190+
t.Log("Microarchitecture level:", CPU.X64Level())
190191
t.Log("Cacheline bytes:", CPU.CacheLine)
191192
t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
192193
t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")

testdata/getall.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
//go:build ignore
2+
13
package main
24

35
import (
46
"archive/zip"
57
_ "bytes"
68
"fmt"
7-
"golang.org/x/net/html"
89
"io"
910
"net/http"
1011
"os"
1112
"strings"
13+
14+
"golang.org/x/net/html"
1215
)
1316

1417
// Download all CPUID dumps from http://users.atw.hu/instlatx64/

0 commit comments

Comments
 (0)