Files
LocalAI/pkg/xsysinfo/cpu_test.go
T
manunicholasjacob aca800d003 fix(xsysinfo): cap the default thread count by the container CPU limit
When --threads / LOCALAI_THREADS is unset, LocalAI uses the host's
physical core count. Inside a container with a CPU limit (docker --cpus,
a Kubernetes limits.cpu) that starts one thread per host core inside a
smaller CFS quota, so the backend is throttled for most of each period.

Since Go 1.25 the default GOMAXPROCS already follows the affinity mask and
the cgroup CPU limit. Use the smaller of the physical core count and
GOMAXPROCS as the default. Hosts without a limit are unchanged.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: manunicholasjacob <manunicholasjacob@gmail.com>
2026-10-14 06:59:32 -05:00

47 lines
1.2 KiB
Go

package xsysinfo
import (
"math"
"runtime"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("CPU telemetry", func() {
It("reports logical cores, utilization, and one-minute load", func() {
info, err := GetCPUInfo()
Expect(err).ToNot(HaveOccurred())
Expect(info.LogicalCores).To(BeNumerically(">", 0))
Expect(info.UsagePercent).To(BeNumerically(">=", 0))
Expect(info.UsagePercent).To(BeNumerically("<=", 100))
Expect(math.IsNaN(info.Load1)).To(BeFalse())
})
})
var _ = Describe("Default thread count", func() {
It("keeps the physical core count when the runtime may use more CPUs", func() {
Expect(capThreads(8, 20)).To(Equal(8))
Expect(capThreads(8, 8)).To(Equal(8))
})
It("lowers the count to the CPUs the runtime may use", func() {
Expect(capThreads(14, 2)).To(Equal(2))
Expect(capThreads(14, 1)).To(Equal(1))
})
It("ignores a non-positive limit and never returns less than 1", func() {
Expect(capThreads(8, 0)).To(Equal(8))
Expect(capThreads(0, 0)).To(Equal(1))
Expect(capThreads(0, 4)).To(Equal(1))
})
It("follows GOMAXPROCS", func() {
prev := runtime.GOMAXPROCS(1)
DeferCleanup(func() { runtime.GOMAXPROCS(prev) })
Expect(DefaultThreads()).To(Equal(1))
})
})