@@ -36,15 +36,42 @@ import (
36
36
//
37
37
// https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
38
38
func NumCPU () int {
39
+ return NumCPUWithCustomPath ("" )
40
+ }
41
+
42
+ func NumCPUWithCustomPath (path string ) int {
39
43
cpus := runtime .NumCPU ()
40
44
41
- cgroupPath , err := libcontainercgroups .FindCgroupMountpoint ("" , "cpu" )
42
- if err != nil {
43
- return cpus
45
+ cgroupVersionCheckPath := path
46
+
47
+ if cgroupVersionCheckPath == "" {
48
+ cgroupVersionCheckPath = "/sys/fs/cgroup/"
44
49
}
45
50
46
- cpuQuota := readCgroupFileToInt64 (cgroupPath , "cpu.cfs_quota_us" )
47
- cpuPeriod := readCgroupFileToInt64 (cgroupPath , "cpu.cfs_period_us" )
51
+ cgroupVersion := GetCgroupVersion (cgroupVersionCheckPath )
52
+ cpuQuota := int64 (- 1 )
53
+ cpuPeriod := int64 (- 1 )
54
+
55
+ if cgroupVersion == 1 {
56
+ cgroupPath := ""
57
+ if path == "" {
58
+ cgroupPathRd , err := libcontainercgroups .FindCgroupMountpoint ("" , "cpu" )
59
+ if err != nil {
60
+ return cpus
61
+ }
62
+ cgroupPath = cgroupPathRd
63
+ } else {
64
+ cgroupPath = path
65
+ }
66
+ cpuQuota = readCgroupFileToInt64 (cgroupPath , "cpu.cfs_quota_us" )
67
+ cpuPeriod = readCgroupFileToInt64 (cgroupPath , "cpu.cfs_period_us" )
68
+ } else if cgroupVersion == 2 {
69
+ cgroupPath := "/sys/fs/cgroup/"
70
+ if path != "" {
71
+ cgroupPath = path
72
+ }
73
+ cpuQuota , cpuPeriod = readCgroup2FileToInt64Tuple (cgroupPath , "cpu.max" )
74
+ }
48
75
49
76
if cpuQuota == - 1 || cpuPeriod == - 1 {
50
77
return cpus
@@ -53,16 +80,66 @@ func NumCPU() int {
53
80
return int (math .Ceil (float64 (cpuQuota ) / float64 (cpuPeriod )))
54
81
}
55
82
56
- func readCgroupFileToInt64 (cgroupPath , cgroupFile string ) int64 {
83
+ func GetCgroupVersion (cgroupPath string ) int64 {
84
+ // /sys/fs/cgroup/cgroup.controllers will not exist with cgroupsv1
85
+ if _ , err := os .Stat (filepath .Join (cgroupPath , "cgroup.controllers" )); err == nil {
86
+ return 2
87
+ }
88
+
89
+ return 1
90
+ }
91
+
92
+ func readCgroup2StringToInt64Tuple (cgroupString string ) (quota , period int64 ) {
93
+ // file contents looks like: $MAX $PERIOD
94
+ // $MAX can have value "max" indicating no limit
95
+ // it is possible for $PERIOD to be unset
96
+
97
+ values := strings .Fields (cgroupString )
98
+
99
+ if values [0 ] == "max" {
100
+ return - 1 , - 1
101
+ }
102
+
103
+ cpuQuota , err := strconv .ParseInt (values [0 ], 10 , 64 )
104
+ if err != nil {
105
+ return - 1 , - 1
106
+ }
107
+
108
+ if len (values ) == 1 {
109
+ return cpuQuota , 100000
110
+ }
111
+
112
+ cpuPeriod , err := strconv .ParseInt (values [1 ], 10 , 64 )
113
+ if err != nil {
114
+ return - 1 , - 1
115
+ }
116
+
117
+ return cpuQuota , cpuPeriod
118
+ }
119
+
120
+ func readCgroup2FileToInt64Tuple (cgroupPath , cgroupFile string ) (quota , period int64 ) {
57
121
contents , err := os .ReadFile (filepath .Join (cgroupPath , cgroupFile ))
58
122
if err != nil {
59
- return - 1
123
+ return - 1 , - 1
60
124
}
61
125
62
- strValue := strings .TrimSpace (string (contents ))
126
+ return readCgroup2StringToInt64Tuple (string (contents ))
127
+ }
128
+
129
+ func readCgroupStringToInt64 (contents string ) int64 {
130
+ strValue := strings .TrimSpace (contents )
63
131
if value , err := strconv .ParseInt (strValue , 10 , 64 ); err == nil {
64
132
return value
65
133
}
66
134
67
135
return - 1
68
136
}
137
+
138
+ func readCgroupFileToInt64 (cgroupPath , cgroupFile string ) int64 {
139
+ contents , err := os .ReadFile (filepath .Join (cgroupPath , cgroupFile ))
140
+ if err != nil {
141
+ return - 1
142
+ }
143
+
144
+ return readCgroupStringToInt64 (string (contents ))
145
+ }
0 commit comments