Skip to content

Remove cgroups v1 from commons-go #16859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 17, 2023
Merged
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
47 changes: 0 additions & 47 deletions components/common-go/cgroups/v1/cpu.go

This file was deleted.

54 changes: 0 additions & 54 deletions components/common-go/cgroups/v1/memory.go

This file was deleted.

159 changes: 18 additions & 141 deletions components/ws-daemon/pkg/iws/iws.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (

linuxproc "github.com/c9s/goprocinfo/linux"
"github.com/gitpod-io/gitpod/common-go/cgroups"
v1 "github.com/gitpod-io/gitpod/common-go/cgroups/v1"
v2 "github.com/gitpod-io/gitpod/common-go/cgroups/v2"
"github.com/gitpod-io/gitpod/common-go/log"
"github.com/gitpod-io/gitpod/common-go/tracing"
Expand Down Expand Up @@ -931,7 +930,11 @@ func (wbs *InWorkspaceServiceServer) WorkspaceInfo(ctx context.Context, req *api
return nil, status.Errorf(codes.FailedPrecondition, "could not determine cgroup setup")
}

resources, err := getWorkspaceResourceInfo(wbs.CGroupMountPoint, cgroupPath, unified)
if !unified {
return nil, status.Errorf(codes.FailedPrecondition, "only cgroups v2 is supported")
}

resources, err := getWorkspaceResourceInfo(wbs.CGroupMountPoint, cgroupPath)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
log.WithError(err).Error("could not get resource information")
Expand All @@ -944,38 +947,21 @@ func (wbs *InWorkspaceServiceServer) WorkspaceInfo(ctx context.Context, req *api
}, nil
}

func getWorkspaceResourceInfo(mountPoint, cgroupPath string, unified bool) (*api.Resources, error) {
if unified {
cpu, err := getCpuResourceInfoV2(mountPoint, cgroupPath)
if err != nil {
return nil, err
}

memory, err := getMemoryResourceInfoV2(mountPoint, cgroupPath)
if err != nil {
return nil, err
}

return &api.Resources{
Cpu: cpu,
Memory: memory,
}, nil
} else {
cpu, err := getCpuResourceInfoV1(mountPoint, cgroupPath)
if err != nil {
return nil, err
}

memory, err := getMemoryResourceInfoV1(mountPoint, cgroupPath)
if err != nil {
return nil, err
}
func getWorkspaceResourceInfo(mountPoint, cgroupPath string) (*api.Resources, error) {
cpu, err := getCpuResourceInfoV2(mountPoint, cgroupPath)
if err != nil {
return nil, err
}

return &api.Resources{
Cpu: cpu,
Memory: memory,
}, nil
memory, err := getMemoryResourceInfoV2(mountPoint, cgroupPath)
if err != nil {
return nil, err
}

return &api.Resources{
Cpu: cpu,
Memory: memory,
}, nil
}

func getCpuResourceInfoV2(mountPoint, cgroupPath string) (*api.Cpu, error) {
Expand Down Expand Up @@ -1066,120 +1052,11 @@ func getMemoryResourceInfoV2(mountPoint, cgroupPath string) (*api.Memory, error)
}, nil
}

func getMemoryResourceInfoV1(mountPoint, cgroupPath string) (*api.Memory, error) {
memory := v1.NewMemoryControllerWithMount(mountPoint, cgroupPath)

memoryLimit, err := memory.Limit()
if err != nil {
return nil, err
}

memInfo, err := linuxproc.ReadMemInfo("/proc/meminfo")
if err != nil {
return nil, xerrors.Errorf("failed to read meminfo: %w", err)
}

// if no memory limit has been specified, use total available memory
if memoryLimit == math.MaxUint64 || memoryLimit > memInfo.MemTotal*1024 {
// total memory is specifed on kilobytes -> convert to bytes
memoryLimit = memInfo.MemTotal * 1024
}

usedMemory, err := memory.Usage()
if err != nil {
return nil, xerrors.Errorf("failed to read memory limit: %w", err)
}

stats, err := memory.Stat()
if err != nil {
return nil, xerrors.Errorf("failed to read memory stats: %w", err)
}

if stats.InactiveFileTotal > 0 {
if usedMemory < stats.InactiveFileTotal {
usedMemory = 0
} else {
usedMemory -= stats.InactiveFileTotal
}
}

return &api.Memory{
Limit: int64(memoryLimit),
Used: int64(usedMemory),
}, nil
}

func getCpuResourceInfoV1(mountPoint, cgroupPath string) (*api.Cpu, error) {
cpu := v1.NewCpuControllerWithMount(mountPoint, cgroupPath)

t, err := resolveCPUStatV1(cpu)
if err != nil {
return nil, err
}

time.Sleep(time.Second)

t2, err := resolveCPUStatV1(cpu)
if err != nil {
return nil, err
}

cpuUsage := t2.usage - t.usage
totalTime := t2.uptime - t.uptime
used := cpuUsage / totalTime * 1000

quota, err := cpu.Quota()
if err != nil {
return nil, err
}

// if no cpu limit has been specified, use the number of cores
var limit uint64
if quota == math.MaxUint64 {
content, err := os.ReadFile(filepath.Join(mountPoint, "cpu", cgroupPath, "cpuacct.usage_percpu"))
if err != nil {
return nil, xerrors.Errorf("failed to read cpuacct.usage_percpu: %w", err)
}
limit = uint64(len(strings.Split(strings.TrimSpace(string(content)), " "))) * 1000
} else {
period, err := cpu.Period()
if err != nil {
return nil, err
}

limit = quota / period * 1000
}

return &api.Cpu{
Used: int64(used),
Limit: int64(limit),
}, nil
}

type cpuStat struct {
usage float64
uptime float64
}

func resolveCPUStatV1(cpu *v1.Cpu) (*cpuStat, error) {
usage_ns, err := cpu.Usage()
if err != nil {
return nil, xerrors.Errorf("failed to get cpu usage: %w", err)
}

// convert from nanoseconds to seconds
usage := float64(usage_ns) * 1e-9
uptime, err := readProcUptime()
if err != nil {
return nil, err
}

return &cpuStat{
usage: usage,
uptime: uptime,
}, nil
}

func resolveCPUStatV2(cpu *v2.Cpu) (*cpuStat, error) {
stats, err := cpu.Stat()
if err != nil {
Expand Down