git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cpuinfo/cpuid_test.go (about)

     1  // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
     2  
     3  package cpuinfo
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestLastID(t *testing.T) {
    12  	if lastID.String() != "lastID" {
    13  		t.Fatal("stringer not updated, run go generate")
    14  	}
    15  }
    16  
    17  func 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.
    25  func 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, "Stepping:", CPU.Stepping)
    38  	t.Log("Features:", 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  
    49  func 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:", 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  }
    70  func 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  
    93  func 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  
   104  func 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
   117  func 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  
   139  func 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
   175  func 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
   185  func 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
   195  func 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()
   202  func 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  
   212  func 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()
   219  func TestLogicalCPU(t *testing.T) {
   220  	t.Log("Currently executing on cpu:", CPU.LogicalCPU())
   221  }
   222  
   223  func 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.
   236  func 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  
   247  func TestCombineFeatures(t *testing.T) {
   248  	cpu := CPU
   249  	for i := FeatureID(0); i < lastID; i++ {
   250  		if cpu.Has(i) != cpu.HasAll(CombineFeatures(i)) {
   251  			t.Errorf("id %d:%s mismatch", i, i.String())
   252  		}
   253  	}
   254  }
   255  
   256  func BenchmarkFlags(b *testing.B) {
   257  	var a bool
   258  	var cpu = CPU
   259  	b.Run("ids", func(b *testing.B) {
   260  		for i := 0; i < b.N; i++ {
   261  			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
   262  		}
   263  		_ = a
   264  	})
   265  	b.Run("features", func(b *testing.B) {
   266  		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)
   267  		for i := 0; i < b.N; i++ {
   268  			a = cpu.HasAll(f) || a
   269  		}
   270  		_ = a
   271  	})
   272  	b.Run("id", func(b *testing.B) {
   273  		for i := 0; i < b.N; i++ {
   274  			a = cpu.Has(CMOV) || a
   275  		}
   276  		_ = a
   277  	})
   278  	b.Run("feature", func(b *testing.B) {
   279  		f := CombineFeatures(CMOV)
   280  		for i := 0; i < b.N; i++ {
   281  			a = cpu.HasAll(f) || a
   282  		}
   283  		_ = a
   284  	})
   285  }