impr: std/cpuinfo: use documented impl ; support JS (#23911)

Currently `cpuinfo.countProcessor` uses hard-coded `HW_AVAILCPU=25` for
both MacOS and BSD;

However,

[There is no HW_AVAILCPU on FreeBSD, NetBSD, and OpenBSD](
https://bugs.webkit.org/show_bug.cgi?id=132542)

Also, `HW_AVAILCPU` is undocmented in MacOS,
while `sysctlbyname("hw.logicalcpu",...)` is documented and used
by many other languages' implementations, like
[Haskell](https://gitlab.haskell.org/ghc/ghc/-/blob/master/rts/posix/OSThreads.c?ref_type=heads#L376)

---

This PR:

- use `importc` value instead of hard-coded values for `HW_*` macros.
- use "hw.logicialcpu" over undocumented HW_AVAILCPU.
- reduce 2 elements of `mib` array when calling `sysctl` as they're no
use.
This commit is contained in:
lit
2024-08-11 23:32:58 +08:00
committed by GitHub
parent fbf9e94145
commit e0e698be9a

View File

@@ -15,75 +15,96 @@ runnableExamples:
include "system/inclrtl"
when defined(posix) and not (defined(macosx) or defined(bsd)):
import std/posix
when defined(js):
import std/jsffi
proc countProcessorsImpl(): int =
when defined(nodejs):
let jsOs = require("os")
let jsObj = jsOs.cpus().length
else:
# `navigator.hardwareConcurrency`
# works on browser as well as deno.
let navigator{.importcpp.}: JsObject
let jsObj = navigator.hardwareConcurrency
result = jsObj.to int
else:
when defined(posix) and not (defined(macosx) or defined(bsd)):
import std/posix
when defined(windows):
import std/private/win_getsysteminfo
when defined(windows):
import std/private/win_getsysteminfo
when defined(freebsd) or defined(macosx):
{.emit: "#include <sys/types.h>".}
when defined(freebsd) or defined(macosx):
{.emit: "#include <sys/types.h>".}
when defined(openbsd) or defined(netbsd):
{.emit: "#include <sys/param.h>".}
when defined(openbsd) or defined(netbsd):
{.emit: "#include <sys/param.h>".}
when defined(macosx) or defined(bsd):
# we HAVE to emit param.h before sysctl.h so we cannot use .header here
# either. The amount of archaic bullshit in Poonix based OSes is just insane.
{.emit: "#include <sys/sysctl.h>".}
const
CTL_HW = 6
HW_AVAILCPU = 25
HW_NCPU = 3
proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
a: var csize_t, b: pointer, c: csize_t): cint {.
importc: "sysctl", nodecl.}
when defined(macosx) or defined(bsd):
# we HAVE to emit param.h before sysctl.h so we cannot use .header here
# either. The amount of archaic bullshit in Poonix based OSes is just insane.
{.emit: "#include <sys/sysctl.h>".}
{.push nodecl.}
when defined(macosx):
proc sysctlbyname(name: cstring,
oldp: pointer, oldlenp: var csize_t,
newp: pointer, newlen: csize_t): cint {.importc.}
let
CTL_HW{.importc.}: cint
HW_NCPU{.importc.}: cint
proc sysctl[I: static[int]](name: var array[I, cint], namelen: cuint,
oldp: pointer, oldlenp: var csize_t,
newp: pointer, newlen: csize_t): cint {.importc.}
{.pop.}
when defined(genode):
import genode/env
when defined(genode):
import genode/env
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
importcpp: "@->cpu().affinity_space().total()".}
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
importcpp: "@->cpu().affinity_space().total()".}
when defined(haiku):
type
SystemInfo {.importc: "system_info", header: "<OS.h>".} = object
cpuCount {.importc: "cpu_count".}: uint32
proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info",
header: "<OS.h>".}
proc countProcessorsImpl(): int {.inline.} =
when defined(windows):
var
si: SystemInfo
getSystemInfo(addr si)
result = int(si.dwNumberOfProcessors)
elif defined(macosx) or defined(bsd):
let dest = addr result
var len = sizeof(result).csize_t
when defined(macosx):
# alias of "hw.activecpu"
if sysctlbyname("hw.logicalcpu", dest, len, nil, 0) == 0:
return
var mib = [CTL_HW, HW_NCPU]
if sysctl(mib, 2, dest, len, nil, 0) == 0:
return
elif defined(hpux):
result = mpctl(MPC_GETNUMSPUS, nil, nil)
elif defined(irix):
var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
result = sysconf(SC_NPROC_ONLN)
elif defined(genode):
result = runtimeEnv.affinitySpaceTotal().int
elif defined(haiku):
var sysinfo: SystemInfo
if getSystemInfo(addr sysinfo) == 0:
result = sysinfo.cpuCount.int
else:
result = sysconf(SC_NPROCESSORS_ONLN)
if result < 0: result = 0
when defined(haiku):
type
SystemInfo {.importc: "system_info", header: "<OS.h>".} = object
cpuCount {.importc: "cpu_count".}: uint32
proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info",
header: "<OS.h>".}
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
## Returns the number of the processors/cores the machine has.
## Returns 0 if it cannot be detected.
when defined(windows):
var
si: SystemInfo
getSystemInfo(addr si)
result = int(si.dwNumberOfProcessors)
elif defined(macosx) or defined(bsd):
var
mib: array[0..3, cint]
numCPU: int
mib[0] = CTL_HW
mib[1] = HW_AVAILCPU
var len = sizeof(numCPU).csize_t
discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
if numCPU < 1:
mib[1] = HW_NCPU
discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
result = numCPU
elif defined(hpux):
result = mpctl(MPC_GETNUMSPUS, nil, nil)
elif defined(irix):
var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
result = sysconf(SC_NPROC_ONLN)
elif defined(genode):
result = runtimeEnv.affinitySpaceTotal().int
elif defined(haiku):
var sysinfo: SystemInfo
if getSystemInfo(addr sysinfo) == 0:
result = sysinfo.cpuCount.int
else:
result = sysconf(SC_NPROCESSORS_ONLN)
if result <= 0: result = 0
countProcessorsImpl()