Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/common-go/cgroups/cgroup.go
2496 views
1
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package cgroups
6
7
import (
8
"bufio"
9
"fmt"
10
"math"
11
"os"
12
"regexp"
13
"strconv"
14
"strings"
15
16
"github.com/containerd/cgroups"
17
v2 "github.com/containerd/cgroups/v2"
18
)
19
20
const DefaultMountPoint = "/sys/fs/cgroup"
21
22
func IsUnifiedCgroupSetup() (bool, error) {
23
return cgroups.Mode() == cgroups.Unified, nil
24
}
25
26
func EnsureCpuControllerEnabled(basePath, cgroupPath string) error {
27
c, err := v2.NewManager(basePath, cgroupPath, &v2.Resources{})
28
if err != nil {
29
return err
30
}
31
32
err = c.ToggleControllers([]string{"cpu"}, v2.Enable)
33
if err != nil {
34
return err
35
}
36
37
return nil
38
}
39
40
type CpuStats struct {
41
UsageTotal uint64
42
UsageUser uint64
43
UsageSystem uint64
44
}
45
46
type MemoryStats struct {
47
InactiveFileTotal uint64
48
}
49
50
func ReadSingleValue(path string) (uint64, error) {
51
content, err := os.ReadFile(path)
52
if err != nil {
53
return 0, err
54
}
55
56
value := strings.TrimSpace(string(content))
57
if value == "max" || value == "-1" {
58
return math.MaxUint64, nil
59
}
60
61
max, err := strconv.ParseUint(value, 10, 64)
62
if err != nil {
63
return 0, err
64
}
65
66
return max, nil
67
}
68
69
func ReadFlatKeyedFile(path string) (map[string]uint64, error) {
70
content, err := os.ReadFile(path)
71
if err != nil {
72
return nil, err
73
}
74
75
entries := strings.Split(strings.TrimSpace(string(content)), "\n")
76
kv := make(map[string]uint64, len(entries))
77
for _, entry := range entries {
78
tokens := strings.Split(entry, " ")
79
if len(tokens) < 2 {
80
continue
81
}
82
v, err := strconv.ParseUint(tokens[1], 10, 64)
83
if err != nil {
84
continue
85
}
86
kv[tokens[0]] = v
87
}
88
89
return kv, nil
90
}
91
92
// Read the total stalled time in microseconds for full and some
93
// It is not necessary to read avg10, avg60 and avg300 as these
94
// are only for convenience. They are calculated as the rate during
95
// the desired time frame.
96
func ReadPSIValue(path string) (PSI, error) {
97
file, err := os.Open(path)
98
if err != nil {
99
return PSI{}, err
100
}
101
defer file.Close()
102
103
scanner := bufio.NewScanner(file)
104
var psi PSI
105
for scanner.Scan() {
106
line := scanner.Text()
107
if err = scanner.Err(); err != nil {
108
return PSI{}, fmt.Errorf("could not read psi file: %w", err)
109
}
110
111
i := strings.LastIndex(line, "total=")
112
if i == -1 {
113
return PSI{}, fmt.Errorf("could not find total stalled time")
114
}
115
116
total, err := strconv.ParseUint(line[i+6:], 10, 64)
117
if err != nil {
118
return PSI{}, fmt.Errorf("could not parse total stalled time: %w", err)
119
}
120
121
if strings.HasPrefix(line, "some") {
122
psi.Some = total
123
}
124
125
if strings.HasPrefix(line, "full") {
126
psi.Full = total
127
}
128
}
129
130
return psi, nil
131
}
132
133
type PSI struct {
134
Some uint64
135
Full uint64
136
}
137
138
var (
139
deviceIORegex = regexp.MustCompile(`([0-9]+):([0-9]+) rbps=([0-9]+) wbps=([0-9]+)`)
140
)
141
142
type DeviceIOMax struct {
143
Major uint64
144
Minor uint64
145
Read uint64
146
Write uint64
147
}
148
149
func ReadIOMax(path string) ([]DeviceIOMax, error) {
150
content, err := os.ReadFile(path)
151
if err != nil {
152
return nil, err
153
}
154
155
var devices []DeviceIOMax
156
for _, line := range strings.Split(string(content), "\n") {
157
line = strings.TrimSpace(line)
158
if line == "" {
159
continue
160
}
161
162
matches := deviceIORegex.FindStringSubmatch(line)
163
if len(matches) != 5 {
164
return nil, fmt.Errorf("invalid line in %s: %s", path, line)
165
}
166
167
major, err := strconv.ParseUint(matches[1], 10, 64)
168
if err != nil {
169
return nil, fmt.Errorf("cannot parse major number: %w", err)
170
}
171
minor, err := strconv.ParseUint(matches[2], 10, 64)
172
if err != nil {
173
return nil, fmt.Errorf("cannot parse minor number: %w", err)
174
}
175
read, err := strconv.ParseUint(matches[3], 10, 64)
176
if err != nil {
177
return nil, fmt.Errorf("cannot parse read bytes: %w", err)
178
}
179
write, err := strconv.ParseUint(matches[4], 10, 64)
180
if err != nil {
181
return nil, fmt.Errorf("cannot parse write bytes: %w", err)
182
}
183
devices = append(devices, DeviceIOMax{
184
Major: major,
185
Minor: minor,
186
Read: read,
187
Write: write,
188
})
189
}
190
191
return devices, nil
192
}
193
194