1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
package maxprocs
import (
"context"
"os"
"runtime"
"strings"
"a.yandex-team.ru/library/go/yandex/deploy/podagent"
"a.yandex-team.ru/library/go/yandex/yplite"
)
const (
SafeProc = 4
MinProc = 2
MaxProc = 8
GoMaxProcEnvName = "GOMAXPROCS"
QloudCPUEnvName = "QLOUD_CPU_GUARANTEE"
InstancectlCPUEnvName = "CPU_GUARANTEE"
DeloyBoxIDName = podagent.EnvBoxIDKey
)
// Adjust adjust the maximum number of CPUs that can be executing.
// Takes a minimum between n and CPU counts and returns the previous setting
func Adjust(n int) int {
if n < MinProc {
n = MinProc
}
nCPU := runtime.NumCPU()
if n < nCPU {
return runtime.GOMAXPROCS(n)
}
return runtime.GOMAXPROCS(nCPU)
}
// AdjustAuto automatically adjust the maximum number of CPUs that can be executing to safe value
// and returns the previous setting
func AdjustAuto() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
if isCgroupsExists() {
return AdjustCgroup()
}
if val, ok := getEnv(InstancectlCPUEnvName); ok {
return applyFloatStringLimit(strings.TrimRight(val, "c"))
}
if val, ok := getEnv(QloudCPUEnvName); ok {
return applyFloatStringLimit(val)
}
if boxID, ok := os.LookupEnv(DeloyBoxIDName); ok {
return adjustYPBox(boxID)
}
if yplite.IsAPIAvailable() {
return AdjustYPLite()
}
return Adjust(SafeProc)
}
// AdjustQloud automatically adjust the maximum number of CPUs in case of Qloud env
// and returns the previous setting
func AdjustQloud() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
if val, ok := getEnv(QloudCPUEnvName); ok {
return applyFloatStringLimit(val)
}
return Adjust(MaxProc)
}
// AdjustYP automatically adjust the maximum number of CPUs in case of YP/Y.Deploy/YP.Hard env
// and returns the previous setting
func AdjustYP() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
if isCgroupsExists() {
return AdjustCgroup()
}
return adjustYPBox(os.Getenv(DeloyBoxIDName))
}
func adjustYPBox(boxID string) int {
resources, err := podagent.NewClient().PodAttributes(context.Background())
if err != nil {
return Adjust(SafeProc)
}
var cpuGuarantee float64
if boxResources, ok := resources.BoxesRequirements[boxID]; ok {
cpuGuarantee = boxResources.CPU.Guarantee / 1000
}
if cpuGuarantee <= 0 {
// if we don't have guarantees for current box, let's use pod guarantees
cpuGuarantee = resources.PodRequirements.CPU.Guarantee / 1000
}
return applyFloatLimit(cpuGuarantee)
}
// AdjustYPLite automatically adjust the maximum number of CPUs in case of YP.Lite env
// and returns the previous setting
func AdjustYPLite() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
podAttributes, err := yplite.FetchPodAttributes()
if err != nil {
return Adjust(SafeProc)
}
return applyFloatLimit(float64(podAttributes.ResourceRequirements.CPU.Guarantee / 1000))
}
// AdjustInstancectl automatically adjust the maximum number of CPUs
// and returns the previous setting
// WARNING: supported only instancectl v1.177+ (https://wiki.yandex-team.ru/runtime-cloud/nanny/instancectl-change-log/#1.177)
func AdjustInstancectl() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
if val, ok := getEnv(InstancectlCPUEnvName); ok {
return applyFloatStringLimit(strings.TrimRight(val, "c"))
}
return Adjust(MaxProc)
}
// AdjustCgroup automatically adjust the maximum number of CPUs based on the CFS quota
// and returns the previous setting.
func AdjustCgroup() int {
if val, ok := getEnv(GoMaxProcEnvName); ok {
return applyIntStringLimit(val)
}
quota, err := getCFSQuota()
if err != nil {
return Adjust(SafeProc)
}
return applyFloatLimit(quota)
}
|