diff --git a/core/os/os.odin b/core/os/os.odin index dd20de17c..e77bf499d 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -261,3 +261,7 @@ heap_allocator :: proc() -> mem.Allocator { data = nil, } } + +processor_core_count :: proc() -> int { + return _processor_core_count() +} diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index b40edb410..456ac1d76 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -314,6 +314,7 @@ foreign libc { @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring --- + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -771,6 +772,18 @@ get_page_size :: proc() -> int { return page_size } +@(private) +_processor_core_count :: proc() -> int { + count : int = 0 + count_size := size_of(count) + if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 { + if count > 0 { + return count + } + } + + return 1 +} _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 2a0381a5d..eacbae97a 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -287,6 +287,7 @@ foreign libc { @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -702,6 +703,19 @@ get_page_size :: proc() -> int { return page_size } +@(private) +_processor_core_count :: proc() -> int { + count : int = 0 + count_size := size_of(count) + if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 { + if count > 0 { + return count + } + } + + return 1 +} + _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index ac40b8cde..6f2196504 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -404,6 +404,7 @@ foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- + @(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- @@ -878,6 +879,10 @@ get_page_size :: proc() -> int { return page_size } +@(private) +_processor_core_count :: proc() -> int { + return int(_unix_get_nprocs()) +} _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 0375107ca..3423c1692 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -269,6 +269,7 @@ foreign libc { @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- + @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- @@ -704,6 +705,12 @@ get_page_size :: proc() -> int { return page_size } +_SC_NPROCESSORS_ONLN :: 503 + +@(private) +_processor_core_count :: proc() -> int { + return int(_sysconf(_SC_NPROCESSORS_ONLN)) +} _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)) @@ -711,4 +718,4 @@ _alloc_command_line_arguments :: proc() -> []string { res[i] = string(arg) } return res -} \ No newline at end of file +} diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 70f7481f0..c407acdb4 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -89,7 +89,10 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { current_thread_id :: proc "contextless" () -> int { return 0 } - +@(private) +_processor_core_count :: proc() -> int { + return 1 +} file_size :: proc(fd: Handle) -> (i64, Errno) { stat, err := wasi.fd_filestat_get(wasi.fd_t(fd)) diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index f48f46fa3..f6d8b3997 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -3,6 +3,7 @@ package os import win32 "core:sys/windows" import "core:runtime" +import "core:intrinsics" Handle :: distinct uintptr File_Time :: distinct u64 @@ -126,7 +127,28 @@ get_page_size :: proc() -> int { return page_size } +@(private) +_processor_core_count :: proc() -> int { + length : win32.DWORD = 0 + result := win32.GetLogicalProcessorInformation(nil, &length) + thread_count := 0 + if !result && win32.GetLastError() == 122 && length > 0 { + processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator) + + result = win32.GetLogicalProcessorInformation(&processors[0], &length) + if result { + for processor in processors { + if processor.Relationship == .RelationProcessorCore { + thread := intrinsics.count_ones(processor.ProcessorMask) + thread_count += int(thread) + } + } + } + } + + return thread_count +} exit :: proc "contextless" (code: int) -> ! { runtime._cleanup_runtime_contextless() @@ -214,4 +236,4 @@ is_windows_10 :: proc() -> bool { is_windows_11 :: proc() -> bool { osvi := get_windows_version_w() return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF) -} \ No newline at end of file +} diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 3eb42a3ad..6def41c5d 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -370,6 +370,8 @@ foreign kernel32 { lpTotalNumberOfBytes: PULARGE_INTEGER, lpTotalNumberOfFreeBytes: PULARGE_INTEGER, ) -> BOOL --- + + GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL --- } @@ -999,3 +1001,49 @@ foreign kernel32 { ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID --- SwitchToFiber :: proc(lpFiber: LPVOID) --- } + +LOGICAL_PROCESSOR_RELATIONSHIP :: enum c_int { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationProcessorDie, + RelationNumaNodeEx, + RelationProcessorModule, + RelationAll = 0xffff, +} + +PROCESSOR_CACHE_TYPE :: enum c_int { + CacheUnified, + CacheInstruction, + CacheData, + CacheTrace, +} + +CACHE_DESCRIPTOR :: struct { + Level: BYTE, + Associativity: BYTE, + LineSize: WORD, + Size: DWORD, + Type: PROCESSOR_CACHE_TYPE, +} + +ProcessorCore :: struct { + Flags: BYTE, +} +NumaNode :: struct { + NodeNumber: DWORD, +} +DUMMYUNIONNAME_u :: struct #raw_union { + Core: ProcessorCore, + Node: NumaNode, + Cache: CACHE_DESCRIPTOR, + Reserved: [2]ULONGLONG, +} + +SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { + ProcessorMask: ULONG_PTR, + Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, + DummyUnion: DUMMYUNIONNAME_u, +}