github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/cpuid/mockcpu_test.go (about)

     1  package cpuid
     2  
     3  import (
     4  	"archive/zip"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  )
    11  
    12  type fakecpuid map[uint32][][]uint32
    13  
    14  type idfuncs struct {
    15  	cpuid   func(op uint32) (eax, ebx, ecx, edx uint32)
    16  	cpuidex func(op, op2 uint32) (eax, ebx, ecx, edx uint32)
    17  	xgetbv  func(index uint32) (eax, edx uint32)
    18  }
    19  
    20  func (f fakecpuid) String() string {
    21  	var out = make([]string, 0, len(f))
    22  	for key, val := range f {
    23  		for _, v := range val {
    24  			out = append(out, fmt.Sprintf("CPUID %08x: [%08x, %08x, %08x, %08x]", key, v[0], v[1], v[2], v[3]))
    25  		}
    26  	}
    27  	sorter := sort.StringSlice(out)
    28  	sort.Sort(&sorter)
    29  	return strings.Join(sorter, "\n")
    30  }
    31  
    32  func mockCPU(def []byte) func() {
    33  	lines := strings.Split(string(def), "\n")
    34  	anyfound := false
    35  	fakeID := make(fakecpuid)
    36  	for _, line := range lines {
    37  		line = strings.Trim(line, "\r\t ")
    38  		if !strings.HasPrefix(line, "CPUID") {
    39  			continue
    40  		}
    41  		// Only collect for first cpu
    42  		if strings.HasPrefix(line, "CPUID 00000000") {
    43  			if anyfound {
    44  				break
    45  			}
    46  		}
    47  		if !strings.Contains(line, "-") {
    48  			//continue
    49  		}
    50  		items := strings.Split(line, ":")
    51  		if len(items) < 2 {
    52  			if len(line) == 51 || len(line) == 50 {
    53  				items = []string{line[0:14], line[15:]}
    54  			} else {
    55  				items = strings.Split(line, "\t")
    56  				if len(items) != 2 {
    57  					//fmt.Println("not found:", line, "len:", len(line))
    58  					continue
    59  				}
    60  			}
    61  		}
    62  		items = items[0:2]
    63  		vals := strings.Trim(items[1], "\r\n ")
    64  
    65  		var idV uint32
    66  		n, err := fmt.Sscanf(items[0], "CPUID %x", &idV)
    67  		if err != nil || n != 1 {
    68  			continue
    69  		}
    70  		existing, ok := fakeID[idV]
    71  		if !ok {
    72  			existing = make([][]uint32, 0)
    73  		}
    74  
    75  		values := make([]uint32, 4)
    76  		n, err = fmt.Sscanf(vals, "%x-%x-%x-%x", &values[0], &values[1], &values[2], &values[3])
    77  		if n != 4 || err != nil {
    78  			n, err = fmt.Sscanf(vals, "%x %x %x %x", &values[0], &values[1], &values[2], &values[3])
    79  			if n != 4 || err != nil {
    80  				//fmt.Println("scanned", vals, "got", n, "Err:", err)
    81  				continue
    82  			}
    83  		}
    84  
    85  		existing = append(existing, values)
    86  		fakeID[idV] = existing
    87  		anyfound = true
    88  	}
    89  
    90  	restorer := func(f idfuncs) func() {
    91  		return func() {
    92  			cpuid = f.cpuid
    93  			cpuidex = f.cpuidex
    94  			xgetbv = f.xgetbv
    95  		}
    96  	}(idfuncs{cpuid: cpuid, cpuidex: cpuidex, xgetbv: xgetbv})
    97  
    98  	cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
    99  		if op == 0x80000000 || op == 0 {
   100  			var ok bool
   101  			_, ok = fakeID[op]
   102  			if !ok {
   103  				return 0, 0, 0, 0
   104  			}
   105  		}
   106  		first, ok := fakeID[op]
   107  		if !ok {
   108  			if op > maxFunctionID() {
   109  				panic(fmt.Sprintf("Base not found: %v, request:%#v\n", fakeID, op))
   110  			} else {
   111  				// we have some entries missing
   112  				return 0, 0, 0, 0
   113  			}
   114  		}
   115  		theid := first[0]
   116  		return theid[0], theid[1], theid[2], theid[3]
   117  	}
   118  	cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
   119  		if op == 0x80000000 {
   120  			var ok bool
   121  			_, ok = fakeID[op]
   122  			if !ok {
   123  				return 0, 0, 0, 0
   124  			}
   125  		}
   126  		first, ok := fakeID[op]
   127  		if !ok {
   128  			if op > maxExtendedFunction() {
   129  				panic(fmt.Sprintf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2))
   130  			} else {
   131  				// we have some entries missing
   132  				return 0, 0, 0, 0
   133  			}
   134  		}
   135  		if int(op2) >= len(first) {
   136  			//fmt.Printf("Extended not found Info: %v, request:%#v, %#v\n", fakeID, op, op2)
   137  			return 0, 0, 0, 0
   138  		}
   139  		theid := first[op2]
   140  		return theid[0], theid[1], theid[2], theid[3]
   141  	}
   142  	xgetbv = func(index uint32) (eax, edx uint32) {
   143  		first, ok := fakeID[1]
   144  		if !ok {
   145  			panic(fmt.Sprintf("XGETBV not supported %v", fakeID))
   146  		}
   147  		second := first[0]
   148  		// ECX bit 26 must be set
   149  		if (second[2] & 1 << 26) == 0 {
   150  			panic(fmt.Sprintf("XGETBV not supported %v", fakeID))
   151  		}
   152  		// We don't have any data to return, unfortunately
   153  		return 0, 0
   154  	}
   155  	return restorer
   156  }
   157  
   158  func TestMocks(t *testing.T) {
   159  	zr, err := zip.OpenReader("testdata/cpuid_data.zip")
   160  	if err != nil {
   161  		t.Skip("No testdata:", err)
   162  	}
   163  	defer zr.Close()
   164  	for _, f := range zr.File {
   165  		rc, err := f.Open()
   166  		if err != nil {
   167  			t.Fatal(err)
   168  		}
   169  		content, err := ioutil.ReadAll(rc)
   170  		if err != nil {
   171  			t.Fatal(err)
   172  		}
   173  		rc.Close()
   174  		t.Log("Opening", f.FileInfo().Name())
   175  		restore := mockCPU(content)
   176  		Detect()
   177  		t.Log("Name:", CPU.BrandName)
   178  		n := maxFunctionID()
   179  		t.Logf("Max Function:0x%x\n", n)
   180  		n = maxExtendedFunction()
   181  		t.Logf("Max Extended Function:0x%x\n", n)
   182  		t.Log("PhysicalCores:", CPU.PhysicalCores)
   183  		t.Log("ThreadsPerCore:", CPU.ThreadsPerCore)
   184  		t.Log("LogicalCores:", CPU.LogicalCores)
   185  		t.Log("Family", CPU.Family, "Model:", CPU.Model)
   186  		t.Log("Features:", CPU.Features)
   187  		t.Log("Cacheline bytes:", CPU.CacheLine)
   188  		t.Log("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
   189  		t.Log("L1 Data Cache:", CPU.Cache.L1D, "bytes")
   190  		t.Log("L2 Cache:", CPU.Cache.L2, "bytes")
   191  		t.Log("L3 Cache:", CPU.Cache.L3, "bytes")
   192  		if CPU.LogicalCores > 0 && CPU.PhysicalCores > 0 {
   193  			if CPU.LogicalCores != CPU.PhysicalCores*CPU.ThreadsPerCore {
   194  				t.Fatalf("Core count mismatch, LogicalCores (%d) != PhysicalCores (%d) * CPU.ThreadsPerCore (%d)",
   195  					CPU.LogicalCores, CPU.PhysicalCores, CPU.ThreadsPerCore)
   196  			}
   197  		}
   198  
   199  		if CPU.ThreadsPerCore > 1 && !CPU.HTT() {
   200  			t.Fatalf("Hyperthreading not detected")
   201  		}
   202  		if CPU.ThreadsPerCore == 1 && CPU.HTT() {
   203  			t.Fatalf("Hyperthreading detected, but only 1 Thread per core")
   204  		}
   205  		restore()
   206  	}
   207  	Detect()
   208  
   209  }