@@ -49,199 +49,14 @@ absl::optional<uint32_t> CgroupCpuUtil::getCpuLimit(Filesystem::Instance& fs) {
4949 const CpuFiles& cpu_files = cpu_files_opt.value ();
5050
5151 // Step 5: Read Actual Limits using cached file paths
52- absl::optional<CpuLimitResult> limit_result_opt = readActualLimits (cpu_files, fs);
53- if (!limit_result_opt .has_value ()) {
52+ absl::optional<double > cpu_ratio = readActualLimits (cpu_files, fs);
53+ if (!cpu_ratio .has_value ()) {
5454 // No valid limit found or unlimited
5555 return absl::nullopt ;
5656 }
5757
5858 // Convert float64 ratio to uint32_t CPU count (rounded up)
59- const uint32_t cpu_limit = static_cast <uint32_t >(std::ceil (limit_result_opt.value ().cpu_ratio ));
60- return cpu_limit;
61- }
62-
63- // Reads CPU limits from cgroup v2 unified hierarchy.
64- // Constructs the full path directly using mount point and relative path.
65- absl::optional<uint32_t > CgroupCpuUtil::getCgroupV2CpuLimit (const std::string& mount_point,
66- Filesystem::Instance& fs) {
67-
68- // Get relative path and version
69- absl::optional<CgroupPathInfo> path_info_opt = getCurrentCgroupPath (fs);
70- if (!path_info_opt.has_value ()) {
71- return absl::nullopt ;
72- }
73- const CgroupPathInfo& path_info = path_info_opt.value ();
74-
75- // Only proceed if this is actually a v2 cgroup
76- if (path_info.version != " v2" ) {
77- return absl::nullopt ;
78- }
79-
80- // Construct full path: mount_point + relative_path + filename
81- const std::string& cgroup_path = path_info.relative_path ;
82- std::string cpu_max_path = absl::StrCat (mount_point, cgroup_path, CGROUP_V2_CPU_MAX_FILE);
83- return readCgroupV2CpuLimit (fs, cpu_max_path);
84- }
85-
86- // Reads CPU limits from cgroup v1 legacy hierarchy.
87- // Constructs the full path directly using mount point and relative path.
88- absl::optional<uint32_t > CgroupCpuUtil::getCgroupV1CpuLimit (const std::string& mount_point,
89- Filesystem::Instance& fs) {
90-
91- // Get relative path and version
92- absl::optional<CgroupPathInfo> path_info_opt = getCurrentCgroupPath (fs);
93- if (!path_info_opt.has_value ()) {
94- return absl::nullopt ;
95- }
96- const CgroupPathInfo& path_info = path_info_opt.value ();
97-
98- // Only proceed if this is actually a v1 cgroup
99- if (path_info.version != " v1" ) {
100- return absl::nullopt ;
101- }
102-
103- // Construct full paths: mount_point + relative_path + filename
104- const std::string& cgroup_path = path_info.relative_path ;
105- std::string quota_path = absl::StrCat (mount_point, cgroup_path, CGROUP_V1_QUOTA_FILE);
106- std::string period_path = absl::StrCat (mount_point, cgroup_path, CGROUP_V1_PERIOD_FILE);
107- return readCgroupV1CpuLimit (fs, quota_path, period_path);
108- }
109-
110- // Parses cgroup v2 cpu.max file to extract CPU limit.
111- // File format: "<quota> <period>" or "max <period>" for unlimited
112- //
113- // Examples:
114- // "150000 100000" = 1.5 CPUs (150ms quota per 100ms period)
115- // "max 100000" = unlimited
116- // "200000 100000" = 2.0 CPUs (200ms quota per 100ms period)
117- //
118- // Returns absl::nullopt for unlimited or parsing errors, valid value for actual limit (rounded up).
119- absl::optional<uint32_t > CgroupCpuUtil::readCgroupV2CpuLimit (Filesystem::Instance& fs,
120- const std::string& cpu_max_path) {
121- const auto result = fs.fileReadToEnd (cpu_max_path);
122- if (!result.ok ()) {
123- // File doesn't exist or can't be read
124- ENVOY_LOG_MISC (warn, " Cannot read cgroup v2 cpu.max file {}: file doesn't exist or read failed" ,
125- cpu_max_path);
126- return absl::nullopt ;
127- }
128-
129- const std::string& content = result.value ();
130-
131- // Validate file content using strict requirements
132- absl::optional<absl::string_view> content_view_opt =
133- validateCgroupFileContent (content, cpu_max_path);
134- if (!content_view_opt.has_value ()) {
135- return absl::nullopt ;
136- }
137- absl::string_view content_view = content_view_opt.value ();
138-
139- // Find space separator
140- size_t space_pos = content_view.find (' ' );
141- if (space_pos == absl::string_view::npos) {
142- ENVOY_LOG_MISC (warn, " Malformed cgroup v2 cpu.max file {}: no space separator" , cpu_max_path);
143- return absl::nullopt ;
144- }
145-
146- absl::string_view quota_str = content_view.substr (0 , space_pos);
147- absl::string_view period_str = content_view.substr (space_pos + 1 );
148-
149- // Check if quota is "max" (unlimited CPU)
150- if (quota_str == " max" ) {
151- return absl::nullopt ; // Unlimited
152- }
153-
154- uint64_t quota, period;
155- if (!absl::SimpleAtoi (quota_str, "a) || !absl::SimpleAtoi (period_str, &period)) {
156- // Parse failure - log warning and return nullopt
157- ENVOY_LOG_MISC (warn, " Failed to parse cgroup v2 cpu.max file {}: quota='{}' period='{}'" ,
158- cpu_max_path, quota_str, period_str);
159- return absl::nullopt ;
160- }
161-
162- if (period == 0 ) {
163- // Division by zero protection
164- ENVOY_LOG_MISC (warn, " Invalid cgroup v2 cpu.max file {}: period cannot be zero" , cpu_max_path);
165- return absl::nullopt ;
166- }
167-
168- // Calculate CPU limit as quota/period ratio, rounded up to next integer
169- // 1.5 CPUs becomes 2 CPUs for worker threads
170- const uint32_t cpu_limit = static_cast <uint32_t >(std::ceil (static_cast <double >(quota) / period));
171- return cpu_limit;
172- }
173-
174- // Parses cgroup v1 CPU quota and period files to extract CPU limit.
175- // Uses separate files: cpu.cfs_quota_us and cpu.cfs_period_us
176- //
177- // Examples:
178- // quota=150000, period=100000 = 1.5 CPUs
179- // quota=-1, period=100000 = unlimited
180- // quota=200000, period=100000 = 2.0 CPUs
181- //
182- // Returns absl::nullopt for unlimited or parsing errors, valid value for actual limit (rounded up).
183- absl::optional<uint32_t > CgroupCpuUtil::readCgroupV1CpuLimit (Filesystem::Instance& fs,
184- const std::string& quota_path,
185- const std::string& period_path) {
186- // Read the quota file (cpu.cfs_quota_us)
187- const auto quota_result = fs.fileReadToEnd (quota_path);
188- if (!quota_result.ok ()) {
189- // File doesn't exist or can't be read
190- ENVOY_LOG_MISC (warn, " Cannot read cgroup v1 quota file {}: file doesn't exist or read failed" ,
191- quota_path);
192- return absl::nullopt ;
193- }
194-
195- // Read the period file (cpu.cfs_period_us)
196- const auto period_result = fs.fileReadToEnd (period_path);
197- if (!period_result.ok ()) {
198- // File doesn't exist or can't be read
199- ENVOY_LOG_MISC (warn, " Cannot read cgroup v1 period file {}: file doesn't exist or read failed" ,
200- period_path);
201- return absl::nullopt ;
202- }
203-
204- const std::string& quota_content = quota_result.value ();
205- const std::string& period_content = period_result.value ();
206-
207- // Validate both files using strict requirements
208- absl::optional<absl::string_view> quota_str_opt =
209- validateCgroupFileContent (quota_content, quota_path);
210- if (!quota_str_opt.has_value ()) {
211- return absl::nullopt ;
212- }
213-
214- absl::optional<absl::string_view> period_str_opt =
215- validateCgroupFileContent (period_content, period_path);
216- if (!period_str_opt.has_value ()) {
217- return absl::nullopt ;
218- }
219-
220- absl::string_view quota_str = quota_str_opt.value ();
221- absl::string_view period_str = period_str_opt.value ();
222-
223- int64_t quota, period;
224- if (!absl::SimpleAtoi (quota_str, "a) || !absl::SimpleAtoi (period_str, &period)) {
225- // Parse failure - log warning and return nullopt
226- ENVOY_LOG_MISC (warn, " Failed to parse cgroup v1 CPU files: quota='{}' period='{}'" , quota_str,
227- period_str);
228- return absl::nullopt ;
229- }
230-
231- // Check if quota is -1 (standard cgroup v1 unlimited indicator)
232- if (quota == -1 ) {
233- return absl::nullopt ; // Unlimited
234- }
235-
236- if (period <= 0 || quota <= 0 ) {
237- // Invalid values - log warning and return nullopt
238- ENVOY_LOG_MISC (warn, " Invalid cgroup v1 CPU values: quota={} period={}" , quota, period);
239- return absl::nullopt ;
240- }
241-
242- // Calculate CPU limit as quota/period ratio, rounded up to next integer
243- // 1.5 CPUs becomes 2 CPUs for worker threads
244- const uint32_t cpu_limit = static_cast <uint32_t >(std::ceil (static_cast <double >(quota) / period));
59+ const uint32_t cpu_limit = static_cast <uint32_t >(std::ceil (cpu_ratio.value ()));
24560 return cpu_limit;
24661}
24762
@@ -338,13 +153,6 @@ absl::optional<CgroupPathInfo> CgroupCpuUtil::getCurrentCgroupPath(Filesystem::I
338153}
339154
340155// Constructs complete cgroup path by combining mount point and process assignment.
341- //
342- // Logic:
343- // 1. Use provided mount point (already discovered)
344- // 2. Call process assignment → Get relative path
345- // 3. Path construction: Combine mount point and relative path
346- // 4. Version determination: Use version from process assignment
347- // 5. Result: Combined path + cgroup version
348156absl::optional<CgroupInfo> CgroupCpuUtil::constructCgroupPath (const std::string& mount_point,
349157 Filesystem::Instance& fs) {
350158
@@ -449,7 +257,7 @@ absl::optional<CpuFiles> CgroupCpuUtil::accessCgroupFiles(const CgroupInfo& cgro
449257}
450258
451259// Reads actual CPU limits from cgroup v1 files with quota/period parsing.
452- absl::optional<CpuLimitResult > CgroupCpuUtil::readActualLimitsV1 (const CpuFiles& cpu_files) {
260+ absl::optional<double > CgroupCpuUtil::readActualLimitsV1 (const CpuFiles& cpu_files) {
453261 // v1: Use cached quota and period content (no re-reading)
454262 const std::string quota_str = std::string (absl::StripAsciiWhitespace (cpu_files.quota_content ));
455263 const std::string period_str = std::string (absl::StripAsciiWhitespace (cpu_files.period_content ));
@@ -474,17 +282,15 @@ absl::optional<CpuLimitResult> CgroupCpuUtil::readActualLimitsV1(const CpuFiles&
474282 }
475283
476284 // Calculate CPU ratio as float64
477- CpuLimitResult result;
478- result.cpu_ratio = static_cast <double >(quota) / static_cast <double >(period);
285+ double cpu_ratio = static_cast <double >(quota) / static_cast <double >(period);
479286
480- ENVOY_LOG_MISC (debug, " cgroup v1 CPU ratio: {} (quota={}, period={})" , result.cpu_ratio , quota,
481- period);
287+ ENVOY_LOG_MISC (debug, " cgroup v1 CPU ratio: {} (quota={}, period={})" , cpu_ratio, quota, period);
482288
483- return result ;
289+ return cpu_ratio ;
484290}
485291
486292// Reads actual CPU limits from cgroup v2 files with "quota period" parsing.
487- absl::optional<CpuLimitResult > CgroupCpuUtil::readActualLimitsV2 (const CpuFiles& cpu_files) {
293+ absl::optional<double > CgroupCpuUtil::readActualLimitsV2 (const CpuFiles& cpu_files) {
488294 // v2: Use cached cpu.max content (no re-reading)
489295 const std::string content = std::string (absl::StripAsciiWhitespace (cpu_files.quota_content ));
490296
@@ -516,13 +322,11 @@ absl::optional<CpuLimitResult> CgroupCpuUtil::readActualLimitsV2(const CpuFiles&
516322 }
517323
518324 // Calculate CPU ratio as float64
519- CpuLimitResult result;
520- result.cpu_ratio = static_cast <double >(quota) / static_cast <double >(period);
325+ double cpu_ratio = static_cast <double >(quota) / static_cast <double >(period);
521326
522- ENVOY_LOG_MISC (debug, " cgroup v2 CPU ratio: {} (quota={}, period={})" , result.cpu_ratio , quota,
523- period);
327+ ENVOY_LOG_MISC (debug, " cgroup v2 CPU ratio: {} (quota={}, period={})" , cpu_ratio, quota, period);
524328
525- return result ;
329+ return cpu_ratio ;
526330}
527331
528332// Reads actual CPU limits from cgroup files with version-specific parsing.
@@ -537,8 +341,8 @@ absl::optional<CpuLimitResult> CgroupCpuUtil::readActualLimitsV2(const CpuFiles&
537341// - v1: quota = -1 means no limit
538342// - v2: quota = "max" means no limit
539343// 5. Result: CPU limit as float64 ratio
540- absl::optional<CpuLimitResult > CgroupCpuUtil::readActualLimits (const CpuFiles& cpu_files,
541- Filesystem::Instance& /* fs */ ) {
344+ absl::optional<double > CgroupCpuUtil::readActualLimits (const CpuFiles& cpu_files,
345+ Filesystem::Instance& /* fs */ ) {
542346 if (cpu_files.version == " v1" ) {
543347 return readActualLimitsV1 (cpu_files);
544348 } else if (cpu_files.version == " v2" ) {
@@ -753,7 +557,7 @@ std::string CgroupCpuUtil::unescapePath(const std::string& path) {
753557// 25 21 0:21 / /sys/fs/cgroup/cpu rw,relatime - cgroup cgroup rw,cpu
754558// 26 21 0:22 / /sys/fs/cgroup cgroup2 rw,relatime - cgroup2 cgroup2 rw
755559//
756- // We extract field 5 (mount point) for cgroup/cgroup2 filesystems only.
560+ // We extract field 5 (mount point) for cgroup/cgroup2 filesystem only.
757561//
758562// NOTE: Mount points may contain escaped characters (\040 for space, \134 for backslash, etc.)
759563// and must be unescaped before use.
0 commit comments