mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Set CPU number to CPU quota
When application is not cgroups-aware, it can spawn excessive threads which often defaults to CPU number. Introduce a opt-in flag that will set CPU number accordingly to CPU quota (if available). Fixes #1391
This commit is contained in:
@@ -250,6 +250,12 @@ type Config struct {
|
||||
// multiple tests are run in parallel, since there is no way to pass
|
||||
// parameters to the runtime from docker.
|
||||
TestOnlyTestNameEnv string
|
||||
|
||||
// CPUNumFromQuota sets CPU number count to available CPU quota, using
|
||||
// least integer value greater than or equal to quota.
|
||||
//
|
||||
// E.g. 0.2 CPU quota would result in 1, and 1.9 in 2.
|
||||
CPUNumFromQuota bool
|
||||
}
|
||||
|
||||
// ToFlags returns a slice of flags that correspond to the given Config.
|
||||
@@ -282,6 +288,9 @@ func (c *Config) ToFlags() []string {
|
||||
"--software-gso=" + strconv.FormatBool(c.SoftwareGSO),
|
||||
"--overlayfs-stale-read=" + strconv.FormatBool(c.OverlayfsStaleRead),
|
||||
}
|
||||
if c.CPUNumFromQuota {
|
||||
f = append(f, "--cpu-num-from-quota")
|
||||
}
|
||||
// Only include these if set since it is never to be used by users.
|
||||
if c.TestOnlyAllowRunAsCurrentUserWithoutChroot {
|
||||
f = append(f, "--TESTONLY-unsafe-nonroot=true")
|
||||
|
||||
@@ -101,6 +101,14 @@ func getValue(path, name string) (string, error) {
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func getInt(path, name string) (int, error) {
|
||||
s, err := getValue(path, name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.Atoi(strings.TrimSpace(s))
|
||||
}
|
||||
|
||||
// fillFromAncestor sets the value of a cgroup file from the first ancestor
|
||||
// that has content. It does nothing if the file in 'path' has already been set.
|
||||
func fillFromAncestor(path string) (string, error) {
|
||||
@@ -323,6 +331,22 @@ func (c *Cgroup) Join() (func(), error) {
|
||||
return undo, nil
|
||||
}
|
||||
|
||||
func (c *Cgroup) CPUQuota() (float64, error) {
|
||||
path := c.makePath("cpu")
|
||||
quota, err := getInt(path, "cpu.cfs_quota_us")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
period, err := getInt(path, "cpu.cfs_period_us")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if quota <= 0 || period <= 0 {
|
||||
return -1, err
|
||||
}
|
||||
return float64(quota) / float64(period), nil
|
||||
}
|
||||
|
||||
// NumCPU returns the number of CPUs configured in 'cpuset/cpuset.cpus'.
|
||||
func (c *Cgroup) NumCPU() (int, error) {
|
||||
path := c.makePath("cpuset")
|
||||
|
||||
@@ -82,6 +82,7 @@ var (
|
||||
numNetworkChannels = flag.Int("num-network-channels", 1, "number of underlying channels(FDs) to use for network link endpoints.")
|
||||
rootless = flag.Bool("rootless", false, "it allows the sandbox to be started with a user that is not root. Sandbox and Gofer processes may run with same privileges as current user.")
|
||||
referenceLeakMode = flag.String("ref-leak-mode", "disabled", "sets reference leak check mode: disabled (default), log-names, log-traces.")
|
||||
cpuNumFromQuota = flag.Bool("cpu-num-from-quota", false, "set cpu number to cpu quota (least integer greater than quota value)")
|
||||
|
||||
// Test flags, not to be used outside tests, ever.
|
||||
testOnlyAllowRunAsCurrentUserWithoutChroot = flag.Bool("TESTONLY-unsafe-nonroot", false, "TEST ONLY; do not ever use! This skips many security measures that isolate the host from the sandbox.")
|
||||
@@ -225,6 +226,7 @@ func main() {
|
||||
AlsoLogToStderr: *alsoLogToStderr,
|
||||
ReferenceLeakMode: refsLeakMode,
|
||||
OverlayfsStaleRead: *overlayfsStaleRead,
|
||||
CPUNumFromQuota: *cpuNumFromQuota,
|
||||
|
||||
TestOnlyAllowRunAsCurrentUserWithoutChroot: *testOnlyAllowRunAsCurrentUserWithoutChroot,
|
||||
TestOnlyTestNameEnv: *testOnlyTestNameEnv,
|
||||
|
||||
@@ -18,6 +18,7 @@ package sandbox
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
@@ -631,6 +632,15 @@ func (s *Sandbox) createSandboxProcess(conf *boot.Config, args *Args, startSyncF
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting cpu count from cgroups: %v", err)
|
||||
}
|
||||
if conf.CPUNumFromQuota {
|
||||
quota, err := s.Cgroup.CPUQuota()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting cpu qouta from cgroups: %v", err)
|
||||
}
|
||||
if quota > 0 {
|
||||
cpuNum = int(math.Ceil(quota))
|
||||
}
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "--cpu-num", strconv.Itoa(cpuNum))
|
||||
|
||||
mem, err := s.Cgroup.MemoryLimit()
|
||||
|
||||
Reference in New Issue
Block a user