Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions internal/runtimehandlerhooks/high_performance_hooks_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/cri-o/cri-o/internal/log"
"github.com/cri-o/cri-o/internal/oci"
crioannotations "github.com/cri-o/cri-o/pkg/annotations"
"github.com/cri-o/cri-o/pkg/config"
"github.com/cri-o/cri-o/utils/cmdrunner"
)

Expand Down Expand Up @@ -68,6 +69,7 @@ type HighPerformanceHooks struct {
irqSMPAffinityFileLock sync.Mutex
irqBalanceConfigFileLock sync.Mutex
sharedCPUs string
execCPUAffinity config.ExecCPUAffinityType
irqSMPAffinityFile string
}

Expand All @@ -78,30 +80,78 @@ func (h *HighPerformanceHooks) PreCreate(ctx context.Context, specgen *generate.
return nil
}

if requestedSharedCPUs(s.Annotations(), c.CRIContainer().GetMetadata().GetName()) {
if isContainerCPUsSpecEmpty(specgen.Config) {
return fmt.Errorf("no cpus found for container %q", c.Name())
}
var (
exclusiveCPUSet cpuset.CPUSet
sharedCPUSet cpuset.CPUSet
err error
)

if !isContainerCPUsSpecEmpty(specgen.Config) {
cpusString := specgen.Config.Linux.Resources.CPU.Cpus

exclusiveCPUs, err := cpuset.Parse(cpusString)
exclusiveCPUSet, err = cpuset.Parse(cpusString)
if err != nil {
return fmt.Errorf("failed to parse container %q cpus: %w", c.Name(), err)
}
}

if h.sharedCPUs == "" {
return fmt.Errorf("shared CPUs were requested for container %q but none are defined", c.Name())
if requestedSharedCPUs(s.Annotations(), c.CRIContainer().GetMetadata().GetName()) {
if exclusiveCPUSet.IsEmpty() {
return fmt.Errorf("no cpus found for container %q", c.Name())
}

sharedCPUSet, err := cpuset.Parse(h.sharedCPUs)
sharedCPUSet, err = cpuset.Parse(h.sharedCPUs)
if err != nil {
return fmt.Errorf("failed to parse shared cpus: %w", err)
}

if sharedCPUSet.IsEmpty() {
return fmt.Errorf("shared CPUs were requested for container %q but none are defined", c.Name())
}

// We must inject the environment variables in the PreCreate stage,
// because in the PreStart stage the process is already constructed.
// by the low-level runtime and the environment variables are already finalized.
injectCpusetEnv(specgen, &exclusiveCPUs, &sharedCPUSet)
injectCpusetEnv(specgen, &exclusiveCPUSet, &sharedCPUSet)
}

return h.setExecCPUAffinity(ctx, specgen, &exclusiveCPUSet, &sharedCPUSet)
}

// setExecCPUAffinity sets ExecCPUAffinity in the container spec.
func (h *HighPerformanceHooks) setExecCPUAffinity(ctx context.Context, specgen *generate.Generator, exclusiveCPUSet, sharedCPUSet *cpuset.CPUSet) error {
var execCPUSet cpuset.CPUSet

switch h.execCPUAffinity {
case config.ExecCPUAffinityTypeFirst:
switch {
case sharedCPUSet != nil && !sharedCPUSet.IsEmpty():
// List() is sorted, so [0] should be the least CPU.
execCPUSet = cpuset.New(sharedCPUSet.List()[0])
case exclusiveCPUSet != nil && !exclusiveCPUSet.IsEmpty():
execCPUSet = cpuset.New(exclusiveCPUSet.List()[0])
default:
log.Errorf(ctx, "ExecCPUAffinityType %s is set, but no CPUSet is available. Falling back to default.", h.execCPUAffinity)
}
case config.ExecCPUAffinityTypeDefault:
// Don't set ExecCPUAffinity, which means using runtime default.
default:
// This shouldn't happen because there's config validation.
return fmt.Errorf("unknown ExecCPUAffinityType %s is used", h.execCPUAffinity)
}

log.Debugf(ctx, "Set ExecCPUAffinity to %q", execCPUSet.String())

if !execCPUSet.IsEmpty() {
if specgen.Config == nil {
specgen.Config = &specs.Spec{}
}

if specgen.Config.Process == nil {
specgen.Config.Process = &specs.Process{}
}

specgen.Config.Process.ExecCPUAffinity = &specs.CPUAffinity{Initial: execCPUSet.String()}
}

return nil
Expand Down
Loading
Loading