in main/vmWatch.go [418:487]
func createAndAssignCgroups(lg *slog.Logger, vmwatchSettings *vmWatchSettings, vmWatchPid int) error {
// get our process and use this to determine the appropriate mount points for the cgroups
myPid := os.Getpid()
memoryLimitInBytes := int64(vmwatchSettings.MemoryLimitInBytes)
telemetry.SendEvent(telemetry.InfoEvent, telemetry.StartVMWatchTask, "Assigning VMWatch process to cgroup")
// check cgroups mode
if cgroups.Mode() == cgroups.Unified {
telemetry.SendEvent(telemetry.InfoEvent, telemetry.StartVMWatchTask, "cgroups v2 detected")
// in cgroup v2, we need to set the period and quota relative to one another.
// Quota is the number of microseconds in the period that process can run
// Period is the length of the period in microseconds
period := uint64(CGroupV2PeriodMs)
cpuQuota := int64(vmwatchSettings.MaxCpuPercentage * 10000)
resources := cgroup2.Resources{
CPU: &cgroup2.CPU{
Max: cgroup2.NewCPUMax(&cpuQuota, &period),
},
Memory: &cgroup2.Memory{
Max: &memoryLimitInBytes,
},
}
// in cgroup v2, it appears that a process already in a cgroup can't create a sub group that limits the same
// kind of resources so we have to do it at the root level. Reference https://manpath.be/f35/7/cgroups#L557
manager, err := cgroup2.NewManager("/sys/fs/cgroup", "/vmwatch.slice", &resources)
if err != nil {
return err
}
err = manager.AddProc(uint64(vmWatchPid))
if err != nil {
return err
}
} else {
telemetry.SendEvent(telemetry.InfoEvent, telemetry.StartVMWatchTask, "cgroups v1 detected")
p := cgroup1.PidPath(myPid)
cpuPath, err := p("cpu")
if err != nil {
return err
}
// in cgroup v1, the interval is implied, 1000 == 1 %
cpuQuota := int64(vmwatchSettings.MaxCpuPercentage * 1000)
memoryLimitInBytes := int64(vmwatchSettings.MemoryLimitInBytes)
s := specs.LinuxResources{
CPU: &specs.LinuxCPU{
Quota: &cpuQuota,
},
Memory: &specs.LinuxMemory{
Limit: &memoryLimitInBytes,
},
}
control, err := cgroup1.New(cgroup1.StaticPath(cpuPath+"/vmwatch.slice"), &s)
if err != nil {
return err
}
err = control.AddProc(uint64(vmWatchPid))
if err != nil {
return err
}
defer control.Delete()
}
return nil
}