18
18
#include < sys/stat.h>
19
19
#include " presto_cpp/main/PeriodicMemoryChecker.h"
20
20
#include " presto_cpp/main/common/Configs.h"
21
+ #include " presto_cpp/main/common/Utils.h"
21
22
22
23
namespace facebook ::presto {
23
24
25
+ using int128_t = __int128_t ;
26
+
24
27
class LinuxMemoryChecker : public PeriodicMemoryChecker {
25
28
public:
26
29
explicit LinuxMemoryChecker (const PeriodicMemoryChecker::Config& config)
@@ -29,13 +32,32 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
29
32
// it's mounted.
30
33
struct stat buffer;
31
34
if ((stat (kCgroupV1Path , &buffer) == 0 )) {
32
- statFile_ = kCgroupV1Path ;
33
- } else if ((stat (kCgroupV2Path , &buffer) == 0 )) {
34
- statFile_ = kCgroupV2Path ;
35
- } else {
36
- statFile_ = " None" ;
35
+ PRESTO_STARTUP_LOG (INFO) << " Using cgroup v1." ;
36
+ if (stat (kCgroupV1MemStatFile , &buffer) == 0 ) {
37
+ memStatFile_ = kCgroupV1MemStatFile ;
38
+ }
39
+ if ((stat (kCgroupV1MaxMemFile , &buffer) == 0 )) {
40
+ memMaxFile_ = kCgroupV1MaxMemFile ;
41
+ }
42
+ }
43
+
44
+ // In cgroup v2.
45
+ else {
46
+ PRESTO_STARTUP_LOG (INFO) << " Using cgroup v2." ;
47
+ if (stat (kCgroupV2MemStatFile , &buffer) == 0 ) {
48
+ memStatFile_ = kCgroupV2MemStatFile ;
49
+ }
50
+ if ((stat (kCgroupV2MaxMemFile , &buffer) == 0 )) {
51
+ memMaxFile_ = kCgroupV2MaxMemFile ;
52
+ }
37
53
}
38
- LOG (INFO) << fmt::format (" Using memory stat file {}" , statFile_);
54
+
55
+ PRESTO_STARTUP_LOG (INFO) << fmt::format (
56
+ " Using memory stat file: {}" ,
57
+ memStatFile_.empty () ? memInfoFile_ : memStatFile_);
58
+ PRESTO_STARTUP_LOG (INFO) << fmt::format (
59
+ " Using memory max file {}" ,
60
+ memMaxFile_.empty () ? memInfoFile_ : memMaxFile_);
39
61
}
40
62
41
63
~LinuxMemoryChecker () override {}
@@ -45,8 +67,92 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
45
67
}
46
68
47
69
void setStatFile (std::string statFile) {
48
- statFile_ = statFile;
49
- LOG (INFO) << fmt::format (" Changed to using memory stat file {}" , statFile_);
70
+ memStatFile_ = statFile;
71
+ LOG (INFO) << fmt::format (
72
+ " Changed to using memory stat file {}" , memStatFile_);
73
+ }
74
+
75
+ // This function is used for testing.
76
+ void setMemMaxFile (const std::string& memMaxFile) {
77
+ memMaxFile_ = memMaxFile;
78
+ }
79
+
80
+ // This function is used for testing.
81
+ void setMemInfoFile (const std::string& memInfoFile) {
82
+ memInfoFile_ = memInfoFile;
83
+ }
84
+
85
+ void start () override {
86
+ // Check system-memory-gb < system-mem-limit-gb < available machine memory
87
+ // of deployment.
88
+ auto * systemConfig = SystemConfig::instance ();
89
+ int64_t systemMemoryInBytes =
90
+ static_cast <int64_t >(systemConfig->systemMemoryGb ()) << 30 ;
91
+ PRESTO_STARTUP_LOG (INFO)
92
+ << fmt::format (" System memory in bytes: {}" , systemMemoryInBytes);
93
+
94
+ PRESTO_STARTUP_LOG (INFO) << fmt::format (
95
+ " System memory limit in bytes: {}" , config_.systemMemLimitBytes );
96
+
97
+ auto availableMemoryOfDeployment = getAvailableMemoryOfDeployment ();
98
+ PRESTO_STARTUP_LOG (INFO) << fmt::format (
99
+ " Available machine memory of deployment in bytes: {}" ,
100
+ availableMemoryOfDeployment);
101
+
102
+ VELOX_CHECK_LE (
103
+ config_.systemMemLimitBytes ,
104
+ availableMemoryOfDeployment,
105
+ " system memory limit = {} bytes is higher than the available machine memory of deployment = {} bytes." ,
106
+ config_.systemMemLimitBytes ,
107
+ availableMemoryOfDeployment);
108
+
109
+ if (config_.systemMemLimitBytes < systemMemoryInBytes) {
110
+ LOG (WARNING) << " system-mem-limit-gb is smaller than system-memory-gb. "
111
+ << " Expected: system-mem-limit-gb >= system-memory-gb." ;
112
+ }
113
+
114
+ PeriodicMemoryChecker::start ();
115
+ }
116
+
117
+ int128_t getAvailableMemoryOfDeployment () {
118
+ // Set the available machine memory of deployment to be the smaller number
119
+ // between /proc/meminfo and memMaxFile_.
120
+ int128_t availableMemoryOfDeployment = 0 ;
121
+ // meminfo's units is in kB.
122
+ folly::gen::byLine (memInfoFile_.c_str ()) |
123
+ [&](const folly::StringPiece& line) -> void {
124
+ if (availableMemoryOfDeployment != 0 ) {
125
+ return ;
126
+ }
127
+ availableMemoryOfDeployment = static_cast <int128_t >(
128
+ extractNumericConfigValueWithRegex (line, kMemTotalRegex ) * 1024 );
129
+ };
130
+
131
+ // For cgroup v1, memory.limit_in_bytes can default to a really big numeric
132
+ // value in bytes like 9223372036854771712 to represent that
133
+ // memory.limit_in_bytes is not set to a value. The default value here is
134
+ // set to PAGE_COUNTER_MAX, which is LONG_MAX/PAGE_SIZE on the 64-bit
135
+ // platform. The default value can vary based upon the platform's PAGE_SIZE.
136
+ // If memory.limit_in_bytes contains a really big numeric value, then we
137
+ // will use MemTotal from /proc/meminfo.
138
+
139
+ // For cgroup v2, memory.max can contain a numeric value in bytes or string
140
+ // "max" which represents no value has been set. If memory.max contains
141
+ // "max", then we will use MemTotal from /proc/meminfo.
142
+ if (!memMaxFile_.empty ()) {
143
+ folly::gen::byLine (memMaxFile_.c_str ()) |
144
+ [&](const folly::StringPiece& line) -> void {
145
+ if (line == " max" ) {
146
+ return ;
147
+ }
148
+ availableMemoryOfDeployment =
149
+ std::min (availableMemoryOfDeployment, folly::to<int128_t >(line));
150
+ return ;
151
+ };
152
+ }
153
+
154
+ // Unit is in bytes.
155
+ return availableMemoryOfDeployment;
50
156
}
51
157
52
158
protected:
@@ -80,8 +186,8 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
80
186
size_t inactiveAnon = 0 ;
81
187
size_t activeAnon = 0 ;
82
188
83
- if (statFile_ != " None " ) {
84
- folly::gen::byLine (statFile_ .c_str ()) |
189
+ if (!memStatFile_. empty () ) {
190
+ folly::gen::byLine (memStatFile_ .c_str ()) |
85
191
[&](const folly::StringPiece& line) -> void {
86
192
if (inactiveAnon == 0 ) {
87
193
inactiveAnon =
@@ -103,7 +209,7 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
103
209
}
104
210
105
211
// Last resort use host machine info.
106
- folly::gen::byLine (" /proc/meminfo " ) |
212
+ folly::gen::byLine (memInfoFile_. c_str () ) |
107
213
[&](const folly::StringPiece& line) -> void {
108
214
if (memAvailable == 0 ) {
109
215
memAvailable =
@@ -143,10 +249,16 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
143
249
const boost::regex kInactiveAnonRegex {R"!( inactive_anon\s*(\d+)\s*)!" };
144
250
const boost::regex kActiveAnonRegex {R"!( active_anon\s*(\d+)\s*)!" };
145
251
const boost::regex kMemAvailableRegex {R"!( MemAvailable:\s*(\d+)\s*kB)!" };
146
- const boost::regex kMemTotalRegex {R"!( MemTotal:\s*(\d+)\s*kB)!" };
147
- const char * kCgroupV1Path = " /sys/fs/cgroup/memory/memory.stat" ;
148
- const char * kCgroupV2Path = " /sys/fs/cgroup/memory.stat" ;
149
- std::string statFile_;
252
+ const boost::regex kMemTotalRegex {R"!( MemTotal:\s*(\d+)\s+kB)!" };
253
+ const char * kCgroupV1Path = " /sys/fs/cgroup/memory" ;
254
+ const char * kCgroupV1MemStatFile = " /sys/fs/cgroup/memory/memory.stat" ;
255
+ const char * kCgroupV2MemStatFile = " /sys/fs/cgroup/memory.stat" ;
256
+ const char * kCgroupV1MaxMemFile =
257
+ " /sys/fs/cgroup/memory/memory.limit_in_bytes" ;
258
+ const char * kCgroupV2MaxMemFile = " /sys/fs/cgroup/memory.max" ;
259
+ std::string memInfoFile_ = " /proc/meminfo" ;
260
+ std::string memStatFile_;
261
+ std::string memMaxFile_;
150
262
151
263
size_t extractNumericConfigValueWithRegex (
152
264
const folly::StringPiece& line,
@@ -164,15 +276,18 @@ class LinuxMemoryChecker : public PeriodicMemoryChecker {
164
276
165
277
folly::Singleton<facebook::presto::PeriodicMemoryChecker> checker (
166
278
[]() -> facebook::presto::PeriodicMemoryChecker* {
167
- PeriodicMemoryChecker::Config config;
168
279
auto * systemConfig = SystemConfig::instance ();
169
- config.systemMemPushbackEnabled =
170
- systemConfig->systemMemPushbackEnabled ();
171
- config.systemMemLimitBytes =
172
- static_cast <uint64_t >(systemConfig->systemMemLimitGb ()) << 30 ;
173
- config.systemMemShrinkBytes =
174
- static_cast <uint64_t >(systemConfig->systemMemShrinkGb ()) << 30 ;
175
- return std::make_unique<LinuxMemoryChecker>(config).release ();
280
+ if (systemConfig->systemMemPushbackEnabled ()) {
281
+ PeriodicMemoryChecker::Config config;
282
+ config.systemMemPushbackEnabled =
283
+ systemConfig->systemMemPushbackEnabled ();
284
+ config.systemMemLimitBytes =
285
+ static_cast <uint64_t >(systemConfig->systemMemLimitGb ()) << 30 ;
286
+ config.systemMemShrinkBytes =
287
+ static_cast <uint64_t >(systemConfig->systemMemShrinkGb ()) << 30 ;
288
+ return std::make_unique<LinuxMemoryChecker>(config).release ();
289
+ }
290
+ return nullptr ;
176
291
});
177
292
178
293
} // namespace facebook::presto
0 commit comments