Files
nomad/client/lib/numalib/detect_darwin.go
Tim Gross 7d73065066 numa: fix scheduler panic due to topology serialization bug (#23284)
The NUMA topology struct field `NodeIDs` is a `idset.Set`, which has no public
members. As a result, this field is never serialized via msgpack and persisted
in state. When `numa.affinity = "prefer"`, the scheduler dereferences this nil
field and panics the scheduler worker.

Ideally we would fix this by adding a msgpack serialization extension, but
because the field already exists and is just always empty, this breaks RPC wire
compatibility across upgrades. Instead, create a new field that's populated at
the same time we populate the more useful `idset.Set`, and repopulate the set on
demand.

Fixes: https://hashicorp.atlassian.net/browse/NET-9924
2024-06-11 08:55:00 -04:00

77 lines
1.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
//go:build darwin
package numalib
import (
"github.com/hashicorp/nomad/client/lib/idset"
"github.com/hashicorp/nomad/client/lib/numalib/hw"
"github.com/shoenig/go-m1cpu"
"golang.org/x/sys/unix"
)
// PlatformScanners returns the set of SystemScanner for macOS.
func PlatformScanners() []SystemScanner {
return []SystemScanner{
new(MacOS),
}
}
const (
nodeID = hw.NodeID(0)
socketID = hw.SocketID(0)
maxSpeed = hw.KHz(0)
)
// MacOS implements SystemScanner for macOS systems (both arm64 and x86).
type MacOS struct{}
func (m *MacOS) ScanSystem(top *Topology) {
// all apple hardware is non-numa; just assume as much
top.nodeIDs = idset.Empty[hw.NodeID]()
top.nodeIDs.Insert(nodeID)
// arch specific detection
switch m1cpu.IsAppleSilicon() {
case true:
m.scanAppleSilicon(top)
case false:
m.scanLegacyX86(top)
}
}
func (m *MacOS) scanAppleSilicon(top *Topology) {
pCoreCount := m1cpu.PCoreCount()
pCoreSpeed := hw.KHz(m1cpu.PCoreHz() / 1000)
eCoreCount := m1cpu.ECoreCount()
eCoreSpeed := hw.KHz(m1cpu.ECoreHz() / 1000)
top.Cores = make([]Core, pCoreCount+eCoreCount)
nthCore := hw.CoreID(0)
for i := 0; i < pCoreCount; i++ {
top.insert(nodeID, socketID, nthCore, Performance, maxSpeed, pCoreSpeed)
nthCore++
}
for i := 0; i < eCoreCount; i++ {
top.insert(nodeID, socketID, nthCore, Efficiency, maxSpeed, eCoreSpeed)
nthCore++
}
}
func (m *MacOS) scanLegacyX86(top *Topology) {
coreCount, _ := unix.SysctlUint32("hw.ncpu")
hz, _ := unix.SysctlUint64("hw.cpufrequency")
coreSpeed := hw.KHz(hz / 1_000)
top.Cores = make([]Core, coreCount)
for i := 0; i < int(coreCount); i++ {
top.insert(nodeID, socketID, hw.CoreID(i), Performance, maxSpeed, coreSpeed)
}
}