| // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. |
| |
| package cpuid |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| ) |
| |
| func TestLastID(t *testing.T) { |
| if lastID.String() != "lastID" { |
| t.Fatal("stringer not updated, run go generate") |
| } |
| } |
| |
| func TestLastVendorID(t *testing.T) { |
| if lastVendor.String() != "lastVendor" { |
| t.Fatal("stringer not updated, run go generate") |
| } |
| } |
| |
| // There is no real way to test a CPU identifier, since results will |
| // obviously differ on each machine. |
| func TestCPUID(t *testing.T) { |
| Detect() |
| n := maxFunctionID() |
| t.Logf("Max Function:0x%x", n) |
| n = maxExtendedFunction() |
| t.Logf("Max Extended Function:0x%x", n) |
| t.Log("VendorString:", CPU.VendorString) |
| t.Log("VendorID:", CPU.VendorID) |
| t.Log("Name:", CPU.BrandName) |
| t.Log("PhysicalCores:", CPU.PhysicalCores) |
| t.Log("ThreadsPerCore:", CPU.ThreadsPerCore) |
| t.Log("LogicalCores:", CPU.LogicalCores) |
| t.Log("Family", CPU.Family, "Model:", CPU.Model, "Stepping:", CPU.Stepping) |
| t.Log("Features:", strings.Join(CPU.FeatureSet(), ",")) |
| t.Log("Cacheline bytes:", CPU.CacheLine) |
| t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes") |
| t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes") |
| t.Log("L2 Cache:", CPU.Cache.L2, "bytes") |
| t.Log("L3 Cache:", CPU.Cache.L3, "bytes") |
| t.Log("Hz:", CPU.Hz, "Hz") |
| t.Log("VM:", CPU.VM()) |
| t.Log("BoostFreq:", CPU.BoostFreq, "Hz") |
| } |
| |
| func TestExample(t *testing.T) { |
| Detect() |
| // Print basic CPU information: |
| fmt.Println("Name:", CPU.BrandName) |
| fmt.Println("PhysicalCores:", CPU.PhysicalCores) |
| fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore) |
| fmt.Println("LogicalCores:", CPU.LogicalCores) |
| fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID) |
| fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ",")) |
| fmt.Println("Cacheline bytes:", CPU.CacheLine) |
| fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes") |
| fmt.Println("L1 Instruction Cache:", CPU.Cache.L1D, "bytes") |
| fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes") |
| fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes") |
| fmt.Println("Frequency", CPU.Hz, "hz") |
| |
| // Test if we have these specific features: |
| if CPU.Supports(SSE, SSE2) { |
| fmt.Println("We have Streaming SIMD 2 Extensions") |
| } |
| } |
| func TestDumpCPUID(t *testing.T) { |
| n := int(maxFunctionID()) |
| for i := 0; i <= n; i++ { |
| a, b, c, d := cpuidex(uint32(i), 0) |
| t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) |
| ex := uint32(1) |
| for { |
| a2, b2, c2, d2 := cpuidex(uint32(i), ex) |
| if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 { |
| break |
| } |
| t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2) |
| a, b, c, d = a2, b2, c2, d2 |
| ex++ |
| } |
| } |
| n2 := maxExtendedFunction() |
| for i := uint32(0x80000000); i <= n2; i++ { |
| a, b, c, d := cpuid(i) |
| t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d) |
| } |
| } |
| |
| func Example() { |
| // Print basic CPU information: |
| fmt.Println("Name:", CPU.BrandName) |
| fmt.Println("PhysicalCores:", CPU.PhysicalCores) |
| fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore) |
| fmt.Println("LogicalCores:", CPU.LogicalCores) |
| fmt.Println("Family", CPU.Family, "Model:", CPU.Model) |
| fmt.Println("Features:", CPU.FeatureSet()) |
| fmt.Println("Cacheline bytes:", CPU.CacheLine) |
| } |
| |
| func TestBrandNameZero(t *testing.T) { |
| if len(CPU.BrandName) > 0 { |
| // Cut out last byte |
| last := []byte(CPU.BrandName[len(CPU.BrandName)-1:]) |
| if last[0] == 0 { |
| t.Fatal("last byte was zero") |
| } else if last[0] == 32 { |
| t.Fatal("whitespace wasn't trimmed") |
| } |
| } |
| } |
| |
| // TestSGX tests SGX detection |
| func TestSGX(t *testing.T) { |
| got := CPU.SGX.Available |
| expected := CPU.featureSet.inSet(SGX) |
| if got != expected { |
| t.Fatalf("SGX: expected %v, got %v", expected, got) |
| } |
| t.Log("SGX Support:", got) |
| |
| if CPU.SGX.Available { |
| var total uint64 = 0 |
| leaves := false |
| for _, s := range CPU.SGX.EPCSections { |
| t.Logf("SGX EPC section: base address 0x%x, size %v", s.BaseAddress, s.EPCSize) |
| total += s.EPCSize |
| leaves = true |
| } |
| if leaves && total == 0 { |
| t.Fatal("SGX enabled without any available EPC memory") |
| } |
| } |
| } |
| |
| func TestHas(t *testing.T) { |
| Detect() |
| defer Detect() |
| feats := CPU.FeatureSet() |
| for _, feat := range feats { |
| f := ParseFeature(feat) |
| if f == UNKNOWN { |
| t.Error("Got unknown feature:", feat) |
| continue |
| } |
| if !CPU.Has(f) { |
| t.Error("CPU.Has returned false, want true") |
| } |
| if !CPU.Supports(f) { |
| t.Error("CPU.Supports returned false, want true") |
| } |
| // Disable it. |
| CPU.Disable(f) |
| if CPU.Has(f) { |
| t.Error("CPU.Has returned true, want false") |
| } |
| if CPU.Supports(f) { |
| t.Error("CPU.Supports returned true, want false") |
| } |
| // Reenable |
| CPU.Enable(f) |
| if !CPU.Has(f) { |
| t.Error("CPU.Has returned false, want true") |
| } |
| if !CPU.Supports(f) { |
| t.Error("CPU.Supports returned false, want true") |
| } |
| } |
| } |
| |
| // TestSGXLC tests SGX Launch Control detection |
| func TestSGXLC(t *testing.T) { |
| got := CPU.SGX.LaunchControl |
| expected := CPU.featureSet.inSet(SGXLC) |
| if got != expected { |
| t.Fatalf("SGX: expected %v, got %v", expected, got) |
| } |
| t.Log("SGX Launch Control Support:", got) |
| } |
| |
| // Test VM function |
| func TestVM(t *testing.T) { |
| got := CPU.VM() |
| expected := CPU.featureSet.inSet(HYPERVISOR) |
| if got != expected { |
| t.Fatalf("TestVM: expected %v, got %v", expected, got) |
| } |
| t.Log("TestVM:", got) |
| } |
| |
| // Test RTCounter function |
| func TestRtCounter(t *testing.T) { |
| a := CPU.RTCounter() |
| b := CPU.RTCounter() |
| t.Log("CPU Counter:", a, b, b-a) |
| } |
| |
| // Prints the value of Ia32TscAux() |
| func TestIa32TscAux(t *testing.T) { |
| ecx := CPU.Ia32TscAux() |
| t.Logf("Ia32TscAux:0x%x\n", ecx) |
| if ecx != 0 { |
| chip := (ecx & 0xFFF000) >> 12 |
| core := ecx & 0xFFF |
| t.Log("Likely chip, core:", chip, core) |
| } |
| } |
| |
| func TestThreadsPerCoreNZ(t *testing.T) { |
| if CPU.ThreadsPerCore == 0 { |
| t.Fatal("threads per core is zero") |
| } |
| } |
| |
| // Prints the value of LogicalCPU() |
| func TestLogicalCPU(t *testing.T) { |
| t.Log("Currently executing on cpu:", CPU.LogicalCPU()) |
| } |
| |
| func TestMaxFunction(t *testing.T) { |
| expect := maxFunctionID() |
| if CPU.maxFunc != expect { |
| t.Fatal("Max function does not match, expected", expect, "but got", CPU.maxFunc) |
| } |
| expect = maxExtendedFunction() |
| if CPU.maxExFunc != expect { |
| t.Fatal("Max Extended function does not match, expected", expect, "but got", CPU.maxFunc) |
| } |
| } |
| |
| // This example will calculate the chip/core number on Linux |
| // Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX. |
| func ExampleCPUInfo_Ia32TscAux() { |
| ecx := CPU.Ia32TscAux() |
| if ecx == 0 { |
| fmt.Println("Unknown CPU ID") |
| return |
| } |
| chip := (ecx & 0xFFF000) >> 12 |
| core := ecx & 0xFFF |
| fmt.Println("Chip, Core:", chip, core) |
| } |
| |
| func TestCombineFeatures(t *testing.T) { |
| cpu := CPU |
| for i := FeatureID(0); i < lastID; i++ { |
| if cpu.Has(i) != cpu.HasAll(CombineFeatures(i)) { |
| t.Errorf("id %d:%s mismatch", i, i.String()) |
| } |
| } |
| } |
| |
| func BenchmarkFlags(b *testing.B) { |
| var a bool |
| var cpu = CPU |
| b.Run("ids", func(b *testing.B) { |
| for i := 0; i < b.N; i++ { |
| a = cpu.Supports(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE) || a |
| } |
| _ = a |
| }) |
| b.Run("features", func(b *testing.B) { |
| f := CombineFeatures(CMOV, CMPXCHG8, X87, FXSR, MMX, SYSCALL, SSE, SSE2, CX16, LAHF, POPCNT, SSE3, SSE4, SSE42, SSSE3, AVX, AVX2, BMI1, BMI2, F16C, FMA3, LZCNT, MOVBE, OSXSAVE) |
| for i := 0; i < b.N; i++ { |
| a = cpu.HasAll(f) || a |
| } |
| _ = a |
| }) |
| b.Run("id", func(b *testing.B) { |
| for i := 0; i < b.N; i++ { |
| a = cpu.Has(CMOV) || a |
| } |
| _ = a |
| }) |
| b.Run("feature", func(b *testing.B) { |
| f := CombineFeatures(CMOV) |
| for i := 0; i < b.N; i++ { |
| a = cpu.HasAll(f) || a |
| } |
| _ = a |
| }) |
| } |