lotus/extern/sector-storage/sched_resources.go

145 lines
4.0 KiB
Go
Raw Normal View History

package sectorstorage
2020-07-09 11:49:01 +00:00
import (
"sync"
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
2020-07-09 11:49:01 +00:00
)
2021-11-29 13:42:20 +00:00
func (a *activeResources) withResources(id storiface.WorkerID, wr storiface.WorkerInfo, r storiface.Resources, locker sync.Locker, cb func() error) error {
for !a.canHandleRequest(r, id, "withResources", wr) {
2020-07-09 11:49:01 +00:00
if a.cond == nil {
a.cond = sync.NewCond(locker)
}
2021-09-15 14:37:27 +00:00
a.waiting++
2020-07-09 11:49:01 +00:00
a.cond.Wait()
2021-09-15 14:37:27 +00:00
a.waiting--
2020-07-09 11:49:01 +00:00
}
2021-06-21 19:49:16 +00:00
a.add(wr.Resources, r)
2020-07-09 11:49:01 +00:00
err := cb()
2021-06-21 19:49:16 +00:00
a.free(wr.Resources, r)
2020-07-09 11:49:01 +00:00
return err
}
2021-09-15 14:37:27 +00:00
// must be called with the same lock as the one passed to withResources
func (a *activeResources) hasWorkWaiting() bool {
return a.waiting > 0
}
2021-11-29 13:42:20 +00:00
func (a *activeResources) add(wr storiface.WorkerResources, r storiface.Resources) {
if r.GPUUtilization > 0 {
a.gpuUsed += r.GPUUtilization
}
a.cpuUse += r.Threads(wr.CPUs, len(wr.GPUs))
2020-07-09 11:49:01 +00:00
a.memUsedMin += r.MinMemory
a.memUsedMax += r.MaxMemory
}
2021-11-29 13:42:20 +00:00
func (a *activeResources) free(wr storiface.WorkerResources, r storiface.Resources) {
if r.GPUUtilization > 0 {
a.gpuUsed -= r.GPUUtilization
2020-07-09 11:49:01 +00:00
}
a.cpuUse -= r.Threads(wr.CPUs, len(wr.GPUs))
2020-07-09 11:49:01 +00:00
a.memUsedMin -= r.MinMemory
a.memUsedMax -= r.MaxMemory
2021-09-15 14:37:27 +00:00
if a.cond != nil {
a.cond.Broadcast()
}
2020-07-09 11:49:01 +00:00
}
2021-06-21 19:49:16 +00:00
// canHandleRequest evaluates if the worker has enough available resources to
// handle the request.
2021-11-29 13:42:20 +00:00
func (a *activeResources) canHandleRequest(needRes storiface.Resources, wid storiface.WorkerID, caller string, info storiface.WorkerInfo) bool {
2021-06-21 19:49:16 +00:00
if info.IgnoreResources {
// shortcircuit; if this worker is ignoring resources, it can always handle the request.
return true
}
2020-07-09 11:49:01 +00:00
2021-06-21 19:49:16 +00:00
res := info.Resources
2020-07-09 11:49:01 +00:00
// TODO: dedupe needRes.BaseMinMemory per task type (don't add if that task is already running)
memNeeded := needRes.MinMemory + needRes.BaseMinMemory
memUsed := a.memUsedMin
// assume that MemUsed can be swapped, so only check it in the vmem Check
memAvail := res.MemPhysical - memUsed
if memNeeded > memAvail {
log.Debugf("sched: not scheduling on worker %s for %s; not enough physical memory - need: %dM, have %dM available", wid, caller, memNeeded/mib, memAvail/mib)
2020-07-09 11:49:01 +00:00
return false
}
vmemNeeded := needRes.MaxMemory + needRes.BaseMinMemory
vmemUsed := a.memUsedMax
workerMemoryReserved := res.MemUsed + res.MemSwapUsed // memory used outside lotus-worker (used by the OS, etc.)
if vmemUsed < workerMemoryReserved {
vmemUsed = workerMemoryReserved
}
vmemAvail := (res.MemPhysical + res.MemSwap) - vmemUsed
2020-07-09 11:49:01 +00:00
if vmemNeeded > vmemAvail {
log.Debugf("sched: not scheduling on worker %s for %s; not enough virtual memory - need: %dM, have %dM available", wid, caller, vmemNeeded/mib, vmemAvail/mib)
2020-07-09 11:49:01 +00:00
return false
}
if a.cpuUse+needRes.Threads(res.CPUs, len(res.GPUs)) > res.CPUs {
log.Debugf("sched: not scheduling on worker %s for %s; not enough threads, need %d, %d in use, target %d", wid, caller, needRes.Threads(res.CPUs, len(res.GPUs)), a.cpuUse, res.CPUs)
return false
2020-07-09 11:49:01 +00:00
}
if len(res.GPUs) > 0 && needRes.GPUUtilization > 0 {
if a.gpuUsed+needRes.GPUUtilization > float64(len(res.GPUs)) {
log.Debugf("sched: not scheduling on worker %s for %s; GPU(s) in use", wid, caller)
2020-07-09 11:49:01 +00:00
return false
}
}
return true
}
func (a *activeResources) utilization(wr storiface.WorkerResources) float64 {
var max float64
cpu := float64(a.cpuUse) / float64(wr.CPUs)
max = cpu
memUsed := a.memUsedMin
if memUsed < wr.MemUsed {
memUsed = wr.MemUsed
}
memMin := float64(memUsed) / float64(wr.MemPhysical)
2020-07-09 11:49:01 +00:00
if memMin > max {
max = memMin
}
vmemUsed := a.memUsedMax
if a.memUsedMax < wr.MemUsed+wr.MemSwapUsed {
vmemUsed = wr.MemUsed + wr.MemSwapUsed
}
memMax := float64(vmemUsed) / float64(wr.MemPhysical+wr.MemSwap)
2020-07-09 11:49:01 +00:00
if memMax > max {
max = memMax
}
return max
}
func (wh *workerHandle) utilization() float64 {
wh.lk.Lock()
u := wh.active.utilization(wh.info.Resources)
u += wh.preparing.utilization(wh.info.Resources)
wh.lk.Unlock()
wh.wndLk.Lock()
for _, window := range wh.activeWindows {
u += window.allocated.utilization(wh.info.Resources)
}
wh.wndLk.Unlock()
return u
}