Skip to content

Commit

Permalink
topology: BSD/MacOS fused + no libc dependency + sysctl auto ID / dyn…
Browse files Browse the repository at this point in the history
…amic ID handling
  • Loading branch information
mratsim committed Dec 26, 2023
1 parent b199fee commit e8c78fd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 69 deletions.
8 changes: 2 additions & 6 deletions constantine/threadpool/primitives/topology.nim
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@

import ../../zoo_exports

when defined(ios) or defined(macosx):
import ./topology_macos
elif defined(bsd):
when defined(bsd) or defined(ios) or defined(macos) or defined(macosx):
import ./topology_bsd
elif defined(windows):
# The following can handle Windows x86 and Windows ARM
Expand Down Expand Up @@ -122,9 +120,7 @@ proc getNumThreadsOS*(): cint {.libExport:"ctt_cpu_get_num_threads_os".} =
## For Simultaneous-Multithreading (SMT often call HyperThreading),
## this returns the number of available logical cores.

when defined(ios) or defined(macos) or defined(macosx):
queryAvailableThreadsMacOS()
elif defined(freebsd):
when defined(bsd) or defined(ios) or defined(macos) or defined(macosx):
queryAvailableThreadsBSD()
elif defined(windows):
queryAvailableThreadsWindows()
Expand Down
89 changes: 66 additions & 23 deletions constantine/threadpool/primitives/topology_bsd.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,74 @@
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.

proc c_printf(fmt: cstring): cint {.sideeffect, importc: "printf", header: "<stdio.h>", varargs, discardable, tags:[WriteIOEffect], noconv.}
proc strerror(errnum: cint): cstring {.importc, header:"<string.h>", noconv.}
proc sysctlbyname(name: cstring, oldp: pointer, oldlenp: ptr csize_t, newp: pointer, newlen: csize_t): int {.importc, header:"<sys/sysctl.h>", noconv.}
# Kernel
# ---------------------------------------------------
# Many sysctl entries are given a dynamic ID (OID_AUTO)
# like kern.smp.cores on FreeBSD: https://github.com/freebsd/freebsd-src/blob/release/14.0.0/sys/kern/subr_smp.c#L107-L109
# or hw.physicalcpu_max on MacOS (no source)
# while others are not available through sysctlbyname
# like hw.availcpu on MacOS
proc sysctl(mib: openArray[cint], oldp: pointer, oldlenp: var csize_t, newp: openArray[byte]): cint {.sideeffect, importc, header:"<sys/sysctl.h>", noconv.}
proc sysctlbyname(name: cstring, oldp: pointer, oldlenp: var csize_t, newp: openArray[byte]): cint {.sideeffect, importc, header:"<sys/sysctl.h>", noconv.}

template queryBsdKernel(arg: untyped): cint =
block:
var r: cint
var size = csize_t sizeof(r)
when arg is string:
const argDesc = arg
let ko = sysctlbyname(arg, r.addr, size, []) != 0
else:
const argDesc = astToStr(arg)
let ko = sysctl(arg, r.addr, size, []) != 0

if ko:
c_printf("[Constantine's Threadpool] sysctl(\"%s\") failure: %s\n", argDesc, strerror(errno))
r = -1
elif r <= 0:
c_printf("[Constantine's Threadpool] sysctl(\"%s\") invalid value: %d\n", argDesc, r)
r = -1
r

# Error handling
# ---------------------------------------------------

proc c_printf(fmt: cstring): cint {.sideeffect, importc: "printf", header: "<stdio.h>", varargs, discardable, tags:[WriteIOEffect].}
proc strerror(errnum: cint): cstring {.importc, header:"<string.h>", noconv.}
var errno {.importc, header: "<errno.h>".}: cint

proc queryNumPhysicalCoresFreeBSD*(): int32 {.inline.} =
var size = csize_t sizeof(result)
let ko = sysctlbyname("kern.smp.cores", result.addr, size.addr, nil, 0) != 0
if ko:
c_printf("[Constantine's Threadpool] sysctlbyname(\"kern.smp.cores\") failure: %s\n", strerror(errno))
result = -1
elif result <= 0:
c_printf("[Constantine's Threadpool] sysctlbyname(\"kern.smp.cores\") invalid value: %d\n", result)
result = -1
# Topology queries
# ---------------------------------------------------

proc queryNumPhysicalCoresFreeBSD*(): cint {.inline.} =
queryBsdKernel"kern.smp.cores"

proc queryNumPhysicalCoresMacOS*(): cint {.inline.} =
# Note:
# - hw.physicalcpu is the number of cores available in current power management mode
# - hw.physicalcpu_max is the max number of cores available this boot.
# i.e. if we may start compute from low power mode with few CPUs "available".
queryBsdKernel"hw.physicalcpu_max"

proc queryAvailableThreadsBSD*(): cint {.inline.} =
# TODO, avoid dependencies on libc
# - MacOS has HW_AVAILCPU
# - OpenBSD and NetBSD have HW_NCPUONLINE
# https://github.com/openbsd/src/blob/master/lib/libc/gen/sysconf.c#L467-L470
# https://github.com/NetBSD/src/blob/trunk/lib/libc/gen/sysconf.c#L372-L375
# - FreeBSD has no "online CPUs" facilities
# and only provides HW_NCPUS
# https://github.com/freebsd/freebsd-src/blob/release/14.0.0/lib/libc/gen/sysconf.c#L583-L589
let SC_NPROCESSORS_ONLN {.importc: "_SC_NPROCESSORS_ONLN", header: "<unistd.h>".}: cint
proc sysconf(name: cint): cint {.importc, header: "<unistd.h>", noconv.}
return sysconf(SC_NPROCESSORS_ONLN)
when defined(ios) or defined(macos) or defined(macosx):
let CTL_HW {.importc.}: cint
let HW_AVAILCPU {.importc.}: cint
queryBsdKernel([CTL_HW, HW_AVAILCPU])
elif defined(freebsd):
# For some reason, sysconf(SC_NPROCESSORS_ONLN) uses HW_NCPUS
# - https://github.com/freebsd/freebsd-src/blob/release/14.0.0/lib/libc/gen/sysconf.c#L583-L589
# instead of its builtin CPU online facility:
# - https://github.com/freebsd/freebsd-src/blob/release/14.0.0/sys/kern/subr_smp.c#L99-L101
queryBsdKernel"kern.smp.cpus"
elif defined(netbsd) or defined(openbsd):
# - OpenBSD and NetBSD have HW_NCPUONLINE
# https://github.com/openbsd/src/blob/master/lib/libc/gen/sysconf.c#L467-L470
# https://github.com/NetBSD/src/blob/trunk/lib/libc/gen/sysconf.c#L372-L375
let CTL_HW {.importc.}: cint
let HW_NCPUONLINE {.importc.}: cint
queryBsdKernel([CTL_HW, HW_NCPUONLINE])
else: # libc dependency and more recent BSDs
let SC_NPROCESSORS_ONLN {.importc: "_SC_NPROCESSORS_ONLN", header: "<unistd.h>".}: cint
proc sysconf(name: cint): cint {.importc, header: "<unistd.h>", noconv.}
return sysconf(SC_NPROCESSORS_ONLN)
40 changes: 0 additions & 40 deletions constantine/threadpool/primitives/topology_macos.nim

This file was deleted.

0 comments on commit e8c78fd

Please sign in to comment.