diff --git a/components/common-go/cgroups/v1/cpu.go b/components/common-go/cgroups/v1/cpu.go deleted file mode 100644 index d70fb2f9455524..00000000000000 --- a/components/common-go/cgroups/v1/cpu.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package cgroups_v1 - -import ( - "path/filepath" - - "github.com/gitpod-io/gitpod/common-go/cgroups" -) - -type Cpu struct { - path string -} - -func NewCpuControllerWithMount(mountPoint, path string) *Cpu { - fullPath := filepath.Join(mountPoint, "cpu", path) - return &Cpu{ - path: fullPath, - } -} - -func NewCpuController(path string) *Cpu { - path = filepath.Join(cgroups.DefaultMountPoint, "cpu", path) - return &Cpu{ - path: path, - } -} - -// Quota returns the cpu quota in microseconds -func (c *Cpu) Quota() (uint64, error) { - path := filepath.Join(c.path, "cpu.cfs_quota_us") - return cgroups.ReadSingleValue(path) -} - -// Period returns the cpu period in microseconds -func (c *Cpu) Period() (uint64, error) { - path := filepath.Join(c.path, "cpu.cfs_period_us") - return cgroups.ReadSingleValue(path) -} - -// Usage returns the cpu usage in nanoseconds -func (c *Cpu) Usage() (uint64, error) { - path := filepath.Join(c.path, "cpuacct.usage") - return cgroups.ReadSingleValue(path) -} diff --git a/components/common-go/cgroups/v1/memory.go b/components/common-go/cgroups/v1/memory.go deleted file mode 100644 index d4afc32711ef0b..00000000000000 --- a/components/common-go/cgroups/v1/memory.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package cgroups_v1 - -import ( - "path/filepath" - - "github.com/gitpod-io/gitpod/common-go/cgroups" -) - -type Memory struct { - path string -} - -func NewMemoryControllerWithMount(mountPoint, path string) *Memory { - fullPath := filepath.Join(mountPoint, "memory", path) - return &Memory{ - path: fullPath, - } -} - -func NewMemoryController(path string) *Memory { - path = filepath.Join(cgroups.DefaultMountPoint, "memory", path) - return &Memory{ - path: path, - } -} - -// Limit returns the memory limit in bytes -func (m *Memory) Limit() (uint64, error) { - path := filepath.Join(m.path, "memory.limit_in_bytes") - return cgroups.ReadSingleValue(path) -} - -// Usage returns the memory usage in bytes -func (m *Memory) Usage() (uint64, error) { - path := filepath.Join(m.path, "memory.usage_in_bytes") - return cgroups.ReadSingleValue(path) -} - -// Stat returns cpu statistics -func (m *Memory) Stat() (*cgroups.MemoryStats, error) { - path := filepath.Join(m.path, "memory.stat") - statMap, err := cgroups.ReadFlatKeyedFile(path) - if err != nil { - return nil, err - } - - return &cgroups.MemoryStats{ - InactiveFileTotal: statMap["total_inactive_file"], - }, nil -} diff --git a/components/ws-daemon/pkg/iws/iws.go b/components/ws-daemon/pkg/iws/iws.go index b3f4b6e431fa27..cc067004afb960 100644 --- a/components/ws-daemon/pkg/iws/iws.go +++ b/components/ws-daemon/pkg/iws/iws.go @@ -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" @@ -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") @@ -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) { @@ -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 {