mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 04:50:29 +00:00
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.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
core/sys/info/cpu_linux_intel.odin
Normal file
38
core/sys/info/cpu_linux_intel.odin
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
core/sys/info/cpu_windows.odin
Normal file
28
core/sys/info/cpu_windows.odin
Normal file
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user