Browse Source

Add core/hyperthread count for Windows and Linux (#5216)

Add core/hyperthread count to `core:sys/info` for Windows and Linux.
TODO: Linux RISCV, Linux ARM, Darwin, and the BSDs.
Jeroen van Rijn 2 months ago
parent
commit
655fab7227

+ 1 - 1
core/crypto/_aes/hw_intel/api.odin

@@ -6,7 +6,7 @@ import "core:sys/info"
 // is_supported returns true iff hardware accelerated AES
 // is supported.
 is_supported :: proc "contextless" () -> bool {
-	features, ok := info.cpu_features.?
+	features, ok := info.cpu.features.?
 	if !ok {
 		return false
 	}

+ 1 - 1
core/crypto/_chacha20/simd128/chacha20_simd128.odin

@@ -227,7 +227,7 @@ is_performant :: proc "contextless" () -> bool {
 			req_features :: info.CPU_Features{.V}
 		}
 
-		features, ok := info.cpu_features.?
+		features, ok := info.cpu.features.?
 		if !ok {
 			return false
 		}

+ 1 - 1
core/crypto/_chacha20/simd256/chacha20_simd256.odin

@@ -41,7 +41,7 @@ _VEC_TWO: simd.u64x4 : {2, 0, 2, 0}
 is_performant :: proc "contextless" () -> bool {
 	req_features :: info.CPU_Features{.avx, .avx2}
 
-	features, ok := info.cpu_features.?
+	features, ok := info.cpu.features.?
 	if !ok {
 		return false
 	}

+ 1 - 1
core/crypto/sha2/sha2_impl_hw_intel.odin

@@ -52,7 +52,7 @@ K_15 :: simd.u64x2{0xa4506ceb90befffa, 0xc67178f2bef9a3f7}
 // is_hardware_accelerated_256 returns true iff hardware accelerated
 // SHA-224/SHA-256 is supported.
 is_hardware_accelerated_256 :: proc "contextless" () -> bool {
-	features, ok := info.cpu_features.?
+	features, ok := info.cpu.features.?
 	if !ok {
 		return false
 	}

+ 1 - 1
core/mem/tlsf/tlsf_internal.odin

@@ -477,7 +477,7 @@ block_mark_as_free :: proc(block: ^Block_Header) {
 }
 
 @(private, no_sanitize_address)
-block_mark_as_used :: proc(block: ^Block_Header, ) {
+block_mark_as_used :: proc(block: ^Block_Header) {
 	next := block_next(block)
 	block_set_prev_used(next)
 	block_set_used(block)

+ 12 - 12
core/sys/freebsd/syscalls.odin

@@ -204,21 +204,21 @@ accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) {
 accept :: proc { accept_T, accept_nil }
 
 getsockname_or_peername :: proc "contextless" (s: Fd, sockaddr: ^$T, is_peer: bool) -> Errno {
-    // sockaddr must contain a valid pointer, or this will segfault because
-    // we're telling the syscall that there's memory available to write to.
-    addrlen: socklen_t = size_of(T)
+	// sockaddr must contain a valid pointer, or this will segfault because
+	// we're telling the syscall that there's memory available to write to.
+	addrlen: socklen_t = size_of(T)
 
-    result, ok := intrinsics.syscall_bsd(
-        is_peer ? SYS_getpeername : SYS_getsockname,
-        cast(uintptr)s,
-        cast(uintptr)sockaddr,
-        cast(uintptr)&addrlen)
+	result, ok := intrinsics.syscall_bsd(
+		is_peer ? SYS_getpeername : SYS_getsockname,
+		cast(uintptr)s,
+		cast(uintptr)sockaddr,
+		cast(uintptr)&addrlen)
 
-    if !ok {
-            return cast(Errno)result
-    }
+	if !ok {
+			return cast(Errno)result
+	}
 
-    return nil
+	return nil
 }
 
 // Get name of connected peer

+ 10 - 6
core/sys/info/cpu_arm.odin

@@ -40,9 +40,13 @@ CPU_Feature :: enum u64 {
 }
 
 CPU_Features :: distinct bit_set[CPU_Feature; u64]
-
-cpu_features: Maybe(CPU_Features)
-cpu_name: Maybe(string)
+CPU :: struct {
+	name:           Maybe(string),
+	features:       Maybe(CPU_Features),
+	physical_cores: int,
+	logical_cores:  int,
+}
+cpu: CPU
 
 @(private)
 cpu_name_buf: [128]byte
@@ -53,7 +57,7 @@ init_cpu_name :: proc "contextless" () {
 
 	when ODIN_OS == .Darwin {
 		if unix.sysctlbyname("machdep.cpu.brand_string", &cpu_name_buf) {
-			cpu_name = string(cstring(rawptr(&cpu_name_buf)))
+			cpu.name = string(cstring(rawptr(&cpu_name_buf)))
 			generic = false
 		}
 	}
@@ -61,10 +65,10 @@ init_cpu_name :: proc "contextless" () {
 	if generic {
 		when ODIN_ARCH == .arm64 {
 			copy(cpu_name_buf[:], "ARM64")
-			cpu_name = string(cpu_name_buf[:len("ARM64")])
+			cpu.name = string(cpu_name_buf[:len("ARM64")])
 		} else {
 			copy(cpu_name_buf[:], "ARM")
-			cpu_name = string(cpu_name_buf[:len("ARM")])
+			cpu.name = string(cpu_name_buf[:len("ARM")])
 		}
 	}
 }

+ 1 - 1
core/sys/info/cpu_darwin_arm64.odin

@@ -5,7 +5,7 @@ import "core:sys/unix"
 @(init, private)
 init_cpu_features :: proc "contextless" () {
 	@(static) features: CPU_Features
-	defer cpu_features = features
+	defer cpu.features = features
 
 	try_set :: proc "contextless" (name: cstring, feature: CPU_Feature) -> (ok: bool) {
 		support: b32

+ 16 - 12
core/sys/info/cpu_intel.odin

@@ -3,12 +3,6 @@ package sysinfo
 
 import "base:intrinsics"
 
-// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
-cpuid :: intrinsics.x86_cpuid
-
-// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
-xgetbv :: intrinsics.x86_xgetbv
-
 CPU_Feature :: enum u64 {
 	aes,       // AES hardware implementation (AES NI)
 	adx,       // Multi-precision add-carry instruction extensions
@@ -49,9 +43,13 @@ CPU_Feature :: enum u64 {
 }
 
 CPU_Features :: distinct bit_set[CPU_Feature; u64]
-
-cpu_features: Maybe(CPU_Features)
-cpu_name:     Maybe(string)
+CPU :: struct {
+	name:           Maybe(string),
+	features:       Maybe(CPU_Features),
+	physical_cores: int, // Initialized by cpu_<os>.odin
+	logical_cores:  int, // Initialized by cpu_<os>.odin
+}
+cpu: CPU
 
 @(init, private)
 init_cpu_features :: proc "c" () {
@@ -88,7 +86,7 @@ init_cpu_features :: proc "c" () {
 	when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
 		// xgetbv is an illegal instruction under FreeBSD 13, OpenBSD 7.1 and NetBSD 10
 		// return before probing further
-		cpu_features = set
+		cpu.features = set
 		return
 	}
 
@@ -151,7 +149,7 @@ init_cpu_features :: proc "c" () {
 	try_set(&set, .rdseed, 18, ebx7)
 	try_set(&set, .adx,    19, ebx7)
 
-	cpu_features = set
+	cpu.features = set
 }
 
 @(private)
@@ -179,5 +177,11 @@ init_cpu_name :: proc "c" () {
 	for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' {
 		brand = brand[:len(brand) - 1]
 	}
-	cpu_name = brand
+	cpu.name = brand
 }
+
+// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
+cpuid :: intrinsics.x86_cpuid
+
+// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
+xgetbv :: intrinsics.x86_xgetbv

+ 1 - 1
core/sys/info/cpu_linux_arm.odin

@@ -17,7 +17,7 @@ init_cpu_features :: proc() {
 	if rerr != .NONE || n == 0 { return }
 
 	features: CPU_Features
-	defer cpu_features = features
+	defer cpu.features = features
 
 	str := string(buf[:n])
 	for line in strings.split_lines_iterator(&str) {

+ 38 - 0
core/sys/info/cpu_linux_intel.odin

@@ -0,0 +1,38 @@
+#+build i386, amd64
+#+build linux
+package sysinfo
+
+import "core:sys/linux"
+import "core:strings"
+import "core:strconv"
+
+@(init, private)
+init_cpu_core_count :: proc() {
+	fd, err := linux.open("/proc/cpuinfo", {})
+	if err != .NONE { return }
+	defer linux.close(fd)
+
+	// This is probably enough right?
+	buf: [4096]byte
+	n, rerr := linux.read(fd, buf[:])
+	if rerr != .NONE || n == 0 { return }
+
+	str := string(buf[:n])
+	for line in strings.split_lines_iterator(&str) {
+		key, _, value := strings.partition(line, ":")
+		key   = strings.trim_space(key)
+		value = strings.trim_space(value)
+
+		if key == "cpu cores" {
+			if num_physical_cores, ok := strconv.parse_int(value); ok {
+				cpu.physical_cores = num_physical_cores
+			}
+		}
+
+		if key == "siblings" {
+			if num_logical_cores, ok := strconv.parse_int(value); ok {
+				cpu.logical_cores = num_logical_cores
+			}
+		}
+	}
+}

+ 2 - 2
core/sys/info/cpu_linux_riscv64.odin

@@ -9,7 +9,7 @@ import "core:sys/linux"
 @(init, private)
 init_cpu_features :: proc() {
 	_features: CPU_Features
-	defer cpu_features = _features
+	defer cpu.features = _features
 
 	HWCAP_Bits :: enum u64 {
 		I = 'I' - 'A',
@@ -109,5 +109,5 @@ init_cpu_features :: proc() {
 
 @(init, private)
 init_cpu_name :: proc() {
-	cpu_name = "RISCV64"
+	cpu.name = "RISCV64"
 }

+ 7 - 3
core/sys/info/cpu_riscv64.odin

@@ -95,6 +95,10 @@ CPU_Feature :: enum u64 {
 }
 
 CPU_Features :: distinct bit_set[CPU_Feature; u64]
-
-cpu_features: Maybe(CPU_Features)
-cpu_name: Maybe(string)
+CPU :: struct {
+	name:           Maybe(string),
+	features:       Maybe(CPU_Features),
+	physical_cores: int,
+	logical_cores:  int,
+}
+cpu: CPU

+ 28 - 0
core/sys/info/cpu_windows.odin

@@ -0,0 +1,28 @@
+package sysinfo
+
+import sys "core:sys/windows"
+import "base:intrinsics"
+
+@(init, private)
+init_cpu_core_count :: proc() {
+	infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
+	defer delete(infos)
+
+	returned_length: sys.DWORD
+	// Query for the required buffer size.
+	if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok {
+		infos = make([]sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returned_length / size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION))
+	}
+
+	// If it still doesn't work, return
+	if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok {
+		return
+	}
+
+	for info in infos {
+		#partial switch info.Relationship {
+		case .RelationProcessorCore: cpu.physical_cores += 1
+		case .RelationNumaNode:      cpu.logical_cores  += int(intrinsics.count_ones(info.ProcessorMask))
+		}
+	}
+}

+ 8 - 6
core/sys/info/doc.odin

@@ -26,13 +26,15 @@ Example:
 	import si "core:sys/info"
 
 	main :: proc() {
-		fmt.printfln("Odin:  %v",    ODIN_VERSION)
-		fmt.printfln("OS:    %v",    si.os_version.as_string)
-		fmt.printfln("OS:    %#v",   si.os_version)
-		fmt.printfln("CPU:   %v",    si.cpu_name)
-		fmt.printfln("RAM:   %#.1M", si.ram.total_ram)
+		fmt.printfln("Odin:      %v",      ODIN_VERSION)
+		fmt.printfln("OS:        %v",      si.os_version.as_string)
+		fmt.printfln("OS:        %#v",     si.os_version)
+		fmt.printfln("CPU:       %v",      si.cpu.name)
+		fmt.printfln("CPU:       %v",      si.cpu.name)
+		fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores)
+		fmt.printfln("RAM:       %#.1M",   si.ram.total_ram)
 
-		// fmt.printfln("Features: %v",      si.cpu_features)
+		// fmt.printfln("Features: %v",      si.cpu.features)
 		// fmt.printfln("MacOS version: %v", si.macos_version)
 
 		fmt.println()

+ 1 - 2
core/sys/windows/kernel32.odin

@@ -857,7 +857,6 @@ MEMORY_RESOURCE_NOTIFICATION_TYPE :: enum c_int {
 LowMemoryResourceNotification  :: MEMORY_RESOURCE_NOTIFICATION_TYPE.LowMemoryResourceNotification
 HighMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.HighMemoryResourceNotification
 
-
 @(default_calling_convention="system")
 foreign kernel32 {
 	CreateMemoryResourceNotification :: proc(
@@ -1194,7 +1193,7 @@ DUMMYUNIONNAME_u :: struct #raw_union {
 SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
 	ProcessorMask: ULONG_PTR,
 	Relationship: LOGICAL_PROCESSOR_RELATIONSHIP,
-	DummyUnion: DUMMYUNIONNAME_u,
+	using DummyUnion: DUMMYUNIONNAME_u,
 }
 
 SYSTEM_POWER_STATUS :: struct {