Files
mesh-sdk/go/catalogue/yields.go
T

80 lines
2.7 KiB
Go

package catalogue
import (
"strconv"
)
// The build processor share's names (novox/hq ADR 0553 §3, §4), written here as well as in the build modules' package
// (BuildCPUShareSetting, ShareWord, DefaultPercent), so a manifest reader does not reach the build runner's code; a
// test of the build modules keeps them agreeing.
const (
// BuildCPUShareSetting is the node-engine's config value of the node's processor share for its builds, in percent.
BuildCPUShareSetting = "build-cpu-share"
// BuildCPUShareWord is the word the composer gives every yielding module: the node's share, in percent.
BuildCPUShareWord = "MESH_BUILD_CPU_SHARE"
// BuildCPUDefaultPercent is the share where nothing sets one.
BuildCPUDefaultPercent = 50
)
// yieldsOf is how the runtime of its own a module is served by gives way on this node (novox/hq ADR 0553), or nil when
// it does not, and the word its steps size their threads from:
//
// - a module holding a seat that yields (Seat.Yields, the build seats) runs at idle priority under the node's one share
// of its processors: the node-engine's own config build-cpu-share (BuildCPUShareSetting) as this node's layers give
// it, its default where none does. Every yielding module of the node carries the same share, so the node-engine's
// one yielding slice has one quota (ADR 0553 §2, §3).
// - its word: that share (BuildCPUShareWord), which a step divides by its own module's capacity (ADR 0553 §4).
//
// Never a refusal: a share out of range is the default, so a mistyped value bounds the builds at the default and never
// stops the node's whole composition.
func (r Resolution) yieldsOf(m Manifest, with Rendering) (map[string]any, map[string]string) {
if !yields(m) {
return nil, nil
}
engine := Manifest{Module: engineModule}
for _, e := range r.Modules {
if e.Module == engineModule {
engine = e
}
}
share := BuildCPUDefaultPercent
for _, s := range Effective(engine, with.Settings[engineModule]) {
if s.Key == BuildCPUShareSetting {
if n, ok := percentOf(s.Value); ok {
share = n
}
}
}
return map[string]any{"priority": "idle", "cpu-share": share},
map[string]string{BuildCPUShareWord: strconv.Itoa(share)}
}
// yields is whether a module claims a seat that yields.
func yields(m Manifest) bool {
for _, c := range m.Claims {
if s, ok := SeatNamed(c.Name); ok && s.Yields {
return true
}
}
return false
}
// percentOf is a setting's value as a percent from 1 to 100: a number, or a string holding one.
func percentOf(v any) (int, bool) {
var n int
switch x := v.(type) {
case float64:
n = int(x)
case int:
n = x
case string:
var err error
if n, err = strconv.Atoi(x); err != nil {
return 0, false
}
default:
return 0, false
}
return n, n >= 1 && n <= 100
}