Skip to content

Commit e6f7cd9

Browse files
authored
Detect ARM64 affinity cores (#67)
Use `sched_getaffinity` to get a logical/physical core count. This is of course not completely reliable, but is better than nothing. Trust ARMCPUID and try to get some more information, like vendor, etc.
1 parent 05e0b1d commit e6f7cd9

5 files changed

Lines changed: 128 additions & 19 deletions

File tree

cpuid.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ const (
3838
SiS
3939
RDC
4040

41+
Ampere
42+
ARM
43+
Broadcom
44+
Cavium
45+
DEC
46+
Fujitsu
47+
Infineon
48+
Motorola
49+
NVIDIA
50+
AMCC
51+
Qualcomm
52+
Marvell
53+
4154
lastVendor
4255
)
4356

detect_arm64.go

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,16 @@ func initCPU() {
2020
func addInfo(c *CPUInfo, safe bool) {
2121
// Seems to be safe to assume on ARM64
2222
c.CacheLine = 64
23-
if detectOS(c) {
24-
// We could detect values from OS, fine.
25-
return
26-
}
23+
detectOS(c)
2724

2825
// ARM64 disabled since it may crash if interrupt is not intercepted by OS.
29-
if safe && runtime.GOOS != "freebsd" {
26+
if safe && !c.Supports(ARMCPUID) && runtime.GOOS != "freebsd" {
3027
return
3128
}
32-
// midr := getMidr()
29+
midr := getMidr()
3330

3431
// MIDR_EL1 - Main ID Register
32+
// https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/midr_el1
3533
// x--------------------------------------------------x
3634
// | Name | bits | visible |
3735
// |--------------------------------------------------|
@@ -46,11 +44,70 @@ func addInfo(c *CPUInfo, safe bool) {
4644
// | Revision | [3-0] | y |
4745
// x--------------------------------------------------x
4846

49-
// fmt.Printf(" implementer: 0x%02x\n", (midr>>24)&0xff)
50-
// fmt.Printf(" variant: 0x%01x\n", (midr>>20)&0xf)
51-
// fmt.Printf("architecture: 0x%01x\n", (midr>>16)&0xf)
52-
// fmt.Printf(" part num: 0x%03x\n", (midr>>4)&0xfff)
53-
// fmt.Printf(" revision: 0x%01x\n", (midr>>0)&0xf)
47+
switch (midr >> 24) & 0xff {
48+
case 0xC0:
49+
c.VendorString = "Ampere Computing"
50+
c.VendorID = Ampere
51+
case 0x41:
52+
c.VendorString = "Arm Limited"
53+
c.VendorID = ARM
54+
case 0x42:
55+
c.VendorString = "Broadcom Corporation"
56+
c.VendorID = Broadcom
57+
case 0x43:
58+
c.VendorString = "Cavium Inc"
59+
c.VendorID = Cavium
60+
case 0x44:
61+
c.VendorString = "Digital Equipment Corporation"
62+
c.VendorID = DEC
63+
case 0x46:
64+
c.VendorString = "Fujitsu Ltd"
65+
c.VendorID = Fujitsu
66+
case 0x49:
67+
c.VendorString = "Infineon Technologies AG"
68+
c.VendorID = Infineon
69+
case 0x4D:
70+
c.VendorString = "Motorola or Freescale Semiconductor Inc"
71+
c.VendorID = Motorola
72+
case 0x4E:
73+
c.VendorString = "NVIDIA Corporation"
74+
c.VendorID = NVIDIA
75+
case 0x50:
76+
c.VendorString = "Applied Micro Circuits Corporation"
77+
c.VendorID = AMCC
78+
case 0x51:
79+
c.VendorString = "Qualcomm Inc"
80+
c.VendorID = Qualcomm
81+
case 0x56:
82+
c.VendorString = "Marvell International Ltd"
83+
c.VendorID = Marvell
84+
case 0x69:
85+
c.VendorString = "Intel Corporation"
86+
c.VendorID = Intel
87+
}
88+
89+
// Lower 4 bits: Architecture
90+
// Architecture Meaning
91+
// 0b0001 Armv4.
92+
// 0b0010 Armv4T.
93+
// 0b0011 Armv5 (obsolete).
94+
// 0b0100 Armv5T.
95+
// 0b0101 Armv5TE.
96+
// 0b0110 Armv5TEJ.
97+
// 0b0111 Armv6.
98+
// 0b1111 Architectural features are individually identified in the ID_* registers, see 'ID registers'.
99+
// Upper 4 bit: Variant
100+
// An IMPLEMENTATION DEFINED variant number.
101+
// Typically, this field is used to distinguish between different product variants, or major revisions of a product.
102+
c.Family = int(midr>>16) & 0xff
103+
104+
// PartNum, bits [15:4]
105+
// An IMPLEMENTATION DEFINED primary part number for the device.
106+
// On processors implemented by Arm, if the top four bits of the primary
107+
// part number are 0x0 or 0x7, the variant and architecture are encoded differently.
108+
// Revision, bits [3:0]
109+
// An IMPLEMENTATION DEFINED revision number for the device.
110+
c.Model = int(midr) & 0xffff
54111

55112
procFeatures := getProcFeatures()
56113

featureid_string.go

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

os_linux_arm64.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
// license that can be found in the LICENSE file located
66
// here https://github.com/golang/sys/blob/master/LICENSE
77

8-
//+build arm64
9-
//+build linux android
10-
118
package cpuid
129

1310
import (
1411
"encoding/binary"
1512
"io/ioutil"
1613
"runtime"
17-
_ "unsafe" //required for go:linkname
14+
"unsafe"
1815
)
1916

2017
// HWCAP bits.
@@ -49,6 +46,10 @@ const (
4946
var hwcap uint
5047

5148
func detectOS(c *CPUInfo) bool {
49+
// For now assuming no hyperthreading is reasonable.
50+
c.LogicalCores = int(getproccount())
51+
c.PhysicalCores = c.LogicalCores
52+
c.ThreadsPerCore = 1
5253
if hwcap == 0 {
5354
// We did not get values from the runtime.
5455
// Try reading /proc/self/auxv
@@ -131,3 +132,30 @@ func detectOS(c *CPUInfo) bool {
131132
func isSet(hwc uint, value uint) bool {
132133
return hwc&value != 0
133134
}
135+
136+
//go:noescape
137+
//go:linkname sched_getaffinity runtime.sched_getaffinity
138+
func sched_getaffinity(pid, len uintptr, buf *byte) int32
139+
140+
func getproccount() int32 {
141+
// This buffer is huge (8 kB) but we are on the system stack
142+
// and there should be plenty of space (64 kB).
143+
// Also this is a leaf, so we're not holding up the memory for long.
144+
const maxCPUs = 64 * 1024
145+
var buf [maxCPUs / 8]byte
146+
r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
147+
if r < 0 {
148+
return 0
149+
}
150+
n := int32(0)
151+
for _, v := range buf[:r] {
152+
for v != 0 {
153+
n += int32(v & 1)
154+
v >>= 1
155+
}
156+
}
157+
if n == 0 {
158+
n = 1
159+
}
160+
return n
161+
}

os_other_arm64.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
// +build arm64
44
// +build !linux
5-
// +build !android
65
// +build !darwin
76

87
package cpuid

0 commit comments

Comments
 (0)