1// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
2
3package cpuid
4
5import (
6	"fmt"
7	"strings"
8	"testing"
9)
10
11func TestLastID(t *testing.T) {
12	if lastID.String() != "lastID" {
13		t.Fatal("stringer not updated, run go generate")
14	}
15}
16
17func TestLastVendorID(t *testing.T) {
18	if lastVendor.String() != "lastVendor" {
19		t.Fatal("stringer not updated, run go generate")
20	}
21}
22
23// There is no real way to test a CPU identifier, since results will
24// obviously differ on each machine.
25func TestCPUID(t *testing.T) {
26	Detect()
27	n := maxFunctionID()
28	t.Logf("Max Function:0x%x", n)
29	n = maxExtendedFunction()
30	t.Logf("Max Extended Function:0x%x", n)
31	t.Log("VendorString:", CPU.VendorString)
32	t.Log("VendorID:", CPU.VendorID)
33	t.Log("Name:", CPU.BrandName)
34	t.Log("PhysicalCores:", CPU.PhysicalCores)
35	t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
36	t.Log("LogicalCores:", CPU.LogicalCores)
37	t.Log("Family", CPU.Family, "Model:", CPU.Model)
38	t.Log("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
39	t.Log("Cacheline bytes:", CPU.CacheLine)
40	t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
41	t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
42	t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
43	t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
44	t.Log("Hz:", CPU.Hz, "Hz")
45	t.Log("VM:", CPU.VM())
46	t.Log("BoostFreq:", CPU.BoostFreq, "Hz")
47}
48
49func TestExample(t *testing.T) {
50	Detect()
51	// Print basic CPU information:
52	fmt.Println("Name:", CPU.BrandName)
53	fmt.Println("PhysicalCores:", CPU.PhysicalCores)
54	fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
55	fmt.Println("LogicalCores:", CPU.LogicalCores)
56	fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID)
57	fmt.Println("Features:", fmt.Sprintf(strings.Join(CPU.FeatureSet(), ",")))
58	fmt.Println("Cacheline bytes:", CPU.CacheLine)
59	fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes")
60	fmt.Println("L1 Instruction Cache:", CPU.Cache.L1D, "bytes")
61	fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes")
62	fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes")
63	fmt.Println("Frequency", CPU.Hz, "hz")
64
65	// Test if we have these specific features:
66	if CPU.Supports(SSE, SSE2) {
67		fmt.Println("We have Streaming SIMD 2 Extensions")
68	}
69}
70func TestDumpCPUID(t *testing.T) {
71	n := int(maxFunctionID())
72	for i := 0; i <= n; i++ {
73		a, b, c, d := cpuidex(uint32(i), 0)
74		t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
75		ex := uint32(1)
76		for {
77			a2, b2, c2, d2 := cpuidex(uint32(i), ex)
78			if a2 == a && b2 == b && d2 == d || ex > 50 || a2 == 0 {
79				break
80			}
81			t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a2, b2, c2, d2)
82			a, b, c, d = a2, b2, c2, d2
83			ex++
84		}
85	}
86	n2 := maxExtendedFunction()
87	for i := uint32(0x80000000); i <= n2; i++ {
88		a, b, c, d := cpuid(i)
89		t.Logf("CPUID %08x: %08x-%08x-%08x-%08x", i, a, b, c, d)
90	}
91}
92
93func Example() {
94	// Print basic CPU information:
95	fmt.Println("Name:", CPU.BrandName)
96	fmt.Println("PhysicalCores:", CPU.PhysicalCores)
97	fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
98	fmt.Println("LogicalCores:", CPU.LogicalCores)
99	fmt.Println("Family", CPU.Family, "Model:", CPU.Model)
100	fmt.Println("Features:", CPU.FeatureSet())
101	fmt.Println("Cacheline bytes:", CPU.CacheLine)
102}
103
104func TestBrandNameZero(t *testing.T) {
105	if len(CPU.BrandName) > 0 {
106		// Cut out last byte
107		last := []byte(CPU.BrandName[len(CPU.BrandName)-1:])
108		if last[0] == 0 {
109			t.Fatal("last byte was zero")
110		} else if last[0] == 32 {
111			t.Fatal("whitespace wasn't trimmed")
112		}
113	}
114}
115
116// TestSGX tests SGX detection
117func TestSGX(t *testing.T) {
118	got := CPU.SGX.Available
119	expected := CPU.featureSet.inSet(SGX)
120	if got != expected {
121		t.Fatalf("SGX: expected %v, got %v", expected, got)
122	}
123	t.Log("SGX Support:", got)
124
125	if CPU.SGX.Available {
126		var total uint64 = 0
127		leaves := false
128		for _, s := range CPU.SGX.EPCSections {
129			t.Logf("SGX EPC section: base address 0x%x, size %v", s.BaseAddress, s.EPCSize)
130			total += s.EPCSize
131			leaves = true
132		}
133		if leaves && total == 0 {
134			t.Fatal("SGX enabled without any available EPC memory")
135		}
136	}
137}
138
139func TestHas(t *testing.T) {
140	Detect()
141	defer Detect()
142	feats := CPU.FeatureSet()
143	for _, feat := range feats {
144		f := ParseFeature(feat)
145		if f == UNKNOWN {
146			t.Error("Got unknown feature:", feat)
147			continue
148		}
149		if !CPU.Has(f) {
150			t.Error("CPU.Has returned false, want true")
151		}
152		if !CPU.Supports(f) {
153			t.Error("CPU.Supports returned false, want true")
154		}
155		// Disable it.
156		CPU.Disable(f)
157		if CPU.Has(f) {
158			t.Error("CPU.Has returned true, want false")
159		}
160		if CPU.Supports(f) {
161			t.Error("CPU.Supports returned true, want false")
162		}
163		// Reenable
164		CPU.Enable(f)
165		if !CPU.Has(f) {
166			t.Error("CPU.Has returned false, want true")
167		}
168		if !CPU.Supports(f) {
169			t.Error("CPU.Supports returned false, want true")
170		}
171	}
172}
173
174// TestSGXLC tests SGX Launch Control detection
175func TestSGXLC(t *testing.T) {
176	got := CPU.SGX.LaunchControl
177	expected := CPU.featureSet.inSet(SGXLC)
178	if got != expected {
179		t.Fatalf("SGX: expected %v, got %v", expected, got)
180	}
181	t.Log("SGX Launch Control Support:", got)
182}
183
184// Test VM function
185func TestVM(t *testing.T) {
186	got := CPU.VM()
187	expected := CPU.featureSet.inSet(HYPERVISOR)
188	if got != expected {
189		t.Fatalf("TestVM: expected %v, got %v", expected, got)
190	}
191	t.Log("TestVM:", got)
192}
193
194// Test RTCounter function
195func TestRtCounter(t *testing.T) {
196	a := CPU.RTCounter()
197	b := CPU.RTCounter()
198	t.Log("CPU Counter:", a, b, b-a)
199}
200
201// Prints the value of Ia32TscAux()
202func TestIa32TscAux(t *testing.T) {
203	ecx := CPU.Ia32TscAux()
204	t.Logf("Ia32TscAux:0x%x\n", ecx)
205	if ecx != 0 {
206		chip := (ecx & 0xFFF000) >> 12
207		core := ecx & 0xFFF
208		t.Log("Likely chip, core:", chip, core)
209	}
210}
211
212func TestThreadsPerCoreNZ(t *testing.T) {
213	if CPU.ThreadsPerCore == 0 {
214		t.Fatal("threads per core is zero")
215	}
216}
217
218// Prints the value of LogicalCPU()
219func TestLogicalCPU(t *testing.T) {
220	t.Log("Currently executing on cpu:", CPU.LogicalCPU())
221}
222
223func TestMaxFunction(t *testing.T) {
224	expect := maxFunctionID()
225	if CPU.maxFunc != expect {
226		t.Fatal("Max function does not match, expected", expect, "but got", CPU.maxFunc)
227	}
228	expect = maxExtendedFunction()
229	if CPU.maxExFunc != expect {
230		t.Fatal("Max Extended function does not match, expected", expect, "but got", CPU.maxFunc)
231	}
232}
233
234// This example will calculate the chip/core number on Linux
235// Linux encodes numa id (<<12) and core id (8bit) into TSC_AUX.
236func ExampleCPUInfo_Ia32TscAux() {
237	ecx := CPU.Ia32TscAux()
238	if ecx == 0 {
239		fmt.Println("Unknown CPU ID")
240		return
241	}
242	chip := (ecx & 0xFFF000) >> 12
243	core := ecx & 0xFFF
244	fmt.Println("Chip, Core:", chip, core)
245}
246