21 * questions.
22 */
23
24 package jdk.test.lib.containers.cgroup;
25
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.Map;
35 import java.util.Scanner;
36 import java.util.Set;
37 import java.util.stream.Collectors;
38 import java.util.stream.LongStream;
39 import java.util.stream.Stream;
40
41 import jdk.internal.platform.Metrics;
42 import jdk.internal.platform.CgroupV1Metrics;
43
44 public class MetricsTesterCgroupV1 implements CgroupMetricsTester {
45
46 private static long unlimited_minimum = 0x7FFFFFFFFF000000L;
47 long startSysVal;
48 long startUserVal;
49 long startUsage;
50 long startPerCpu[];
51
52 enum Controller {
53 MEMORY("memory"),
54 CPUSET("cpuset"),
55 CPU("cpu"),
56 CPUACCT("cpuacct"),
57 BLKIO("blkio");
58
59 private String value;
60
61 Controller(String value) {
62 this.value = value;
63 }
64
65 public String value() {
110 private static void createSubsystems(String[] line) {
111 if (line.length < 5) return;
112 Path p = Paths.get(line[4]);
113 String subsystemName = p.getFileName().toString();
114 if (subsystemName != null) {
115 for (String subSystem : subsystemName.split(",")) {
116 if (allowedSubSystems.contains(subSystem)) {
117 subSystemPaths.put(subSystem, new String[]{line[3], line[4]});
118 }
119 }
120 }
121 }
122
123 public void setup() {
124 Metrics metrics = Metrics.systemMetrics();
125 // Initialize CPU usage metrics before we do any testing.
126 startSysVal = metrics.getCpuSystemUsage();
127 startUserVal = metrics.getCpuUserUsage();
128 startUsage = metrics.getCpuUsage();
129 startPerCpu = metrics.getPerCpuUsage();
130 if (startPerCpu == null) {
131 startPerCpu = new long[0];
132 }
133
134 try {
135 Stream<String> lines = Files.lines(Paths.get("/proc/self/mountinfo"));
136 lines.filter(line -> line.contains(" - cgroup cgroup "))
137 .map(line -> line.split(" "))
138 .forEach(MetricsTesterCgroupV1::createSubsystems);
139 lines.close();
140
141 lines = Files.lines(Paths.get("/proc/self/cgroup"));
142 lines.map(line -> line.split(":"))
143 .filter(line -> (line.length >= 3))
144 .forEach(MetricsTesterCgroupV1::setPath);
145 lines.close();
146 } catch (IOException e) {
147 }
148 }
149
150 private static String getFileContents(Controller subSystem, String fileName) {
151 String fname = subSystemPaths.get(subSystem.value())[0] + File.separator + fileName;
152 try {
153 return new Scanner(new File(fname)).useDelimiter("\\Z").next();
154 } catch (FileNotFoundException e) {
155 System.err.println("Unable to open : " + fname);
156 return null;
157 }
158 }
159
160 private static long getLongValueFromFile(Controller subSystem, String fileName) {
161 String data = getFileContents(subSystem, fileName);
162 return (data == null || data.isEmpty()) ? 0L : convertStringToLong(data);
163 }
164
165 private static long convertStringToLong(String strval) {
166 return CgroupMetricsTester.convertStringToLong(strval, Long.MAX_VALUE);
167 }
168
169 private static long getLongValueFromFile(Controller subSystem, String metric, String subMetric) {
170 String stats = getFileContents(subSystem, metric);
171 String[] tokens = stats.split("[\\r\\n]+");
172 for (int i = 0; i < tokens.length; i++) {
173 if (tokens[i].startsWith(subMetric)) {
174 String strval = tokens[i].split("\\s+")[1];
175 return convertStringToLong(strval);
176 }
177 }
178 return 0L;
179 }
180
181 private static double getDoubleValueFromFile(Controller subSystem, String fileName) {
182 String data = getFileContents(subSystem, fileName);
183 return data.isEmpty() ? 0.0 : Double.parseDouble(data);
184 }
185
186 private static void fail(Controller system, String metric, long oldVal, long testVal) {
187 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
188 }
189
190 private static void fail(Controller system, String metric, String oldVal, String testVal) {
191 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
192 }
193
194 private static void fail(Controller system, String metric, double oldVal, double testVal) {
195 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
196 }
197
198 private static void fail(Controller system, String metric, boolean oldVal, boolean testVal) {
199 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
200 }
201
202 private static void warn(Controller system, String metric, long oldVal, long testVal) {
203 CgroupMetricsTester.warn(system.value, metric, oldVal, testVal);
204 }
205
206 public void testMemorySubsystem() {
207 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
208
209 // User Memory
210 long oldVal = metrics.getMemoryFailCount();
211 long newVal = getLongValueFromFile(Controller.MEMORY, "memory.failcnt");
212 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
213 fail(Controller.MEMORY, "memory.failcnt", oldVal, newVal);
214 }
215
216 oldVal = metrics.getMemoryLimit();
217 newVal = getLongValueFromFile(Controller.MEMORY, "memory.limit_in_bytes");
218 newVal = newVal > unlimited_minimum ? -1L : newVal;
219 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
220 fail(Controller.MEMORY, "memory.limit_in_bytes", oldVal, newVal);
221 }
222
223 oldVal = metrics.getMemoryMaxUsage();
224 newVal = getLongValueFromFile(Controller.MEMORY, "memory.max_usage_in_bytes");
225 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
226 fail(Controller.MEMORY, "memory.max_usage_in_bytes", oldVal, newVal);
227 }
228
229 oldVal = metrics.getMemoryUsage();
230 newVal = getLongValueFromFile(Controller.MEMORY, "memory.usage_in_bytes");
231 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
232 fail(Controller.MEMORY, "memory.usage_in_bytes", oldVal, newVal);
233 }
234
235 // Kernel memory
236 oldVal = metrics.getKernelMemoryFailCount();
237 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.failcnt");
238 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
239 fail(Controller.MEMORY, "memory.kmem.failcnt", oldVal, newVal);
240 }
241
242 oldVal = metrics.getKernelMemoryLimit();
243 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.limit_in_bytes");
244 newVal = newVal > unlimited_minimum ? -1L : newVal;
245 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
246 fail(Controller.MEMORY, "memory.kmem.limit_in_bytes", oldVal, newVal);
247 }
248
249 oldVal = metrics.getKernelMemoryMaxUsage();
250 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.max_usage_in_bytes");
251 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
252 fail(Controller.MEMORY, "memory.kmem.max_usage_in_bytes", oldVal, newVal);
253 }
254
255 oldVal = metrics.getKernelMemoryUsage();
256 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.usage_in_bytes");
257 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
258 fail(Controller.MEMORY, "memory.kmem.usage_in_bytes", oldVal, newVal);
259 }
260
261 //TCP Memory
262 oldVal = metrics.getTcpMemoryFailCount();
263 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.failcnt");
264 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
265 fail(Controller.MEMORY, "memory.kmem.tcp.failcnt", oldVal, newVal);
266 }
267
268 oldVal = metrics.getTcpMemoryLimit();
269 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes");
270 newVal = newVal > unlimited_minimum ? -1L : newVal;
271 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
272 fail(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes", oldVal, newVal);
273 }
274
275 oldVal = metrics.getTcpMemoryMaxUsage();
276 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes");
277 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
278 fail(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes", oldVal, newVal);
279 }
280
281 oldVal = metrics.getTcpMemoryUsage();
282 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes");
283 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
284 fail(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes", oldVal, newVal);
285 }
286
287 // Memory and Swap
288 oldVal = metrics.getMemoryAndSwapFailCount();
289 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
290 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
291 fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
292 }
293
294 oldVal = metrics.getMemoryAndSwapLimit();
295 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
296 newVal = newVal > unlimited_minimum ? -1L : newVal;
297 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
298 fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
299 }
300
301 oldVal = metrics.getMemoryAndSwapMaxUsage();
302 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
303 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
304 fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
305 }
306
307 oldVal = metrics.getMemoryAndSwapUsage();
308 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
309 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
310 fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
311 }
312
313 oldVal = metrics.getMemorySoftLimit();
314 newVal = getLongValueFromFile(Controller.MEMORY, "memory.soft_limit_in_bytes");
315 newVal = newVal > unlimited_minimum ? -1L : newVal;
316 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
317 fail(Controller.MEMORY, "memory.soft_limit_in_bytes", oldVal, newVal);
318 }
319
320 boolean oomKillEnabled = metrics.isMemoryOOMKillEnabled();
321 boolean newOomKillEnabled = getLongValueFromFile(Controller.MEMORY,
322 "memory.oom_control", "oom_kill_disable") == 0L ? true : false;
323 if (oomKillEnabled != newOomKillEnabled) {
324 throw new RuntimeException("Test failed for - " + Controller.MEMORY.value + ":"
325 + "memory.oom_control:oom_kill_disable" + ", expected ["
326 + oomKillEnabled + "], got [" + newOomKillEnabled + "]");
327 }
328 }
329
330 public void testCpuAccounting() {
331 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
332 long oldVal = metrics.getCpuUsage();
333 long newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.usage");
334
335 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
336 warn(Controller.CPUACCT, "cpuacct.usage", oldVal, newVal);
337 }
338
339 String newValsStr = getFileContents(Controller.CPUACCT, "cpuacct.usage_percpu");
340 Long[] newVals = new Long[0];
341 if (newValsStr != null) {
342 newVals = Stream.of(newValsStr
343 .split("\\s+"))
344 .map(Long::parseLong)
345 .toArray(Long[]::new);
346 }
347 long[] oldValsPrim = metrics.getPerCpuUsage();
348 Long[] oldVals = LongStream.of(oldValsPrim == null ? new long[0] : oldValsPrim)
349 .boxed().toArray(Long[]::new);
350 for (int i = 0; i < oldVals.length; i++) {
351 if (!CgroupMetricsTester.compareWithErrorMargin(oldVals[i], newVals[i])) {
352 warn(Controller.CPUACCT, "cpuacct.usage_percpu", oldVals[i], newVals[i]);
353 }
354 }
355
356 oldVal = metrics.getCpuUserUsage();
357 newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "user");
358 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
359 warn(Controller.CPUACCT, "cpuacct.usage - user", oldVal, newVal);
360 }
361
362 oldVal = metrics.getCpuSystemUsage();
363 newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "system");
364 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
365 warn(Controller.CPUACCT, "cpuacct.usage - system", oldVal, newVal);
366 }
367 }
368
369 public void testCpuSchedulingMetrics() {
370 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
371 long oldVal = metrics.getCpuPeriod();
372 long newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.cfs_period_us");
373 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
374 fail(Controller.CPUACCT, "cpu.cfs_period_us", oldVal, newVal);
391 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_periods");
392 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
393 fail(Controller.CPUACCT, "cpu.stat - nr_periods", oldVal, newVal);
394 }
395
396 oldVal = metrics.getCpuNumThrottled();
397 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_throttled");
398 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
399 fail(Controller.CPUACCT, "cpu.stat - nr_throttled", oldVal, newVal);
400 }
401
402 oldVal = metrics.getCpuThrottledTime();
403 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "throttled_time");
404 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
405 fail(Controller.CPUACCT, "cpu.stat - throttled_time", oldVal, newVal);
406 }
407 }
408
409 public void testCpuSets() {
410 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
411 Integer[] oldVal = Arrays.stream(metrics.getCpuSetCpus()).boxed().toArray(Integer[]::new);
412 Arrays.sort(oldVal);
413
414 String cpusstr = getFileContents(Controller.CPUSET, "cpuset.cpus");
415 // Parse range string in the format 1,2-6,7
416 Integer[] newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
417 Arrays.sort(newVal);
418 if (Arrays.compare(oldVal, newVal) != 0) {
419 fail(Controller.CPUSET, "cpuset.cpus", Arrays.toString(oldVal),
420 Arrays.toString(newVal));
421 }
422
423 int [] cpuSets = metrics.getEffectiveCpuSetCpus();
424
425 // Skip this test if this metric is not supported on this platform
426 if (cpuSets.length != 0) {
427 oldVal = Arrays.stream(cpuSets).boxed().toArray(Integer[]::new);
428 Arrays.sort(oldVal);
429 cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_cpus");
430 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
431 Arrays.sort(newVal);
432 if (Arrays.compare(oldVal, newVal) != 0) {
433 fail(Controller.CPUSET, "cpuset.effective_cpus", Arrays.toString(oldVal),
434 Arrays.toString(newVal));
435 }
436 }
437
438 oldVal = Arrays.stream(metrics.getCpuSetMems()).boxed().toArray(Integer[]::new);
439 Arrays.sort(oldVal);
440 cpusstr = getFileContents(Controller.CPUSET, "cpuset.mems");
441 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
442 Arrays.sort(newVal);
443 if (Arrays.compare(oldVal, newVal) != 0) {
444 fail(Controller.CPUSET, "cpuset.mems", Arrays.toString(oldVal),
445 Arrays.toString(newVal));
446 }
447
448 int [] cpuSetMems = metrics.getEffectiveCpuSetMems();
449
450 // Skip this test if this metric is not supported on this platform
451 if (cpuSetMems.length != 0) {
452 oldVal = Arrays.stream(cpuSetMems).boxed().toArray(Integer[]::new);
453 Arrays.sort(oldVal);
454 cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_mems");
455 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
456 Arrays.sort(newVal);
457 if (Arrays.compare(oldVal, newVal) != 0) {
458 fail(Controller.CPUSET, "cpuset.effective_mems", Arrays.toString(oldVal),
459 Arrays.toString(newVal));
460 }
461 }
462
463 double oldValue = metrics.getCpuSetMemoryPressure();
464 double newValue = getDoubleValueFromFile(Controller.CPUSET, "cpuset.memory_pressure");
465 if (!CgroupMetricsTester.compareWithErrorMargin(oldValue, newValue)) {
466 fail(Controller.CPUSET, "cpuset.memory_pressure", oldValue, newValue);
467 }
468
469 boolean oldV = metrics.isCpuSetMemoryPressureEnabled();
470 boolean newV = getLongValueFromFile(Controller.CPUSET,
471 "cpuset.memory_pressure_enabled") == 1 ? true : false;
472 if (oldV != newV) {
473 fail(Controller.CPUSET, "cpuset.memory_pressure_enabled", oldV, newV);
474 }
475 }
476
477 private void testBlkIO() {
478 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
479 long oldVal = metrics.getBlkIOServiceCount();
480 long newVal = getLongValueFromFile(Controller.BLKIO,
481 "blkio.throttle.io_service_bytes", "Total");
482 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
483 fail(Controller.BLKIO, "blkio.throttle.io_service_bytes - Total",
484 oldVal, newVal);
485 }
486
487 oldVal = metrics.getBlkIOServiced();
488 newVal = getLongValueFromFile(Controller.BLKIO, "blkio.throttle.io_serviced", "Total");
489 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
490 fail(Controller.BLKIO, "blkio.throttle.io_serviced - Total", oldVal, newVal);
491 }
492 }
493
494 public void testCpuConsumption() throws IOException, InterruptedException {
495 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
496 // make system call
497 long newSysVal = metrics.getCpuSystemUsage();
498 long newUserVal = metrics.getCpuUserUsage();
499 long newUsage = metrics.getCpuUsage();
500 long[] newPerCpu = metrics.getPerCpuUsage();
501 if (newPerCpu == null) {
502 newPerCpu = new long[0];
503 }
504
505 // system/user CPU usage counters may be slowly increasing.
506 // allow for equal values for a pass
507 if (newSysVal < startSysVal) {
508 fail(Controller.CPU, "getCpuSystemUsage", newSysVal, startSysVal);
509 }
510
511 // system/user CPU usage counters may be slowly increasing.
512 // allow for equal values for a pass
513 if (newUserVal < startUserVal) {
514 fail(Controller.CPU, "getCpuUserUsage", newUserVal, startUserVal);
515 }
516
517 if (newUsage <= startUsage) {
518 fail(Controller.CPU, "getCpuUsage", newUsage, startUsage);
519 }
520
521 boolean success = false;
522 for (int i = 0; i < startPerCpu.length; i++) {
523 if (newPerCpu[i] > startPerCpu[i]) {
524 success = true;
525 break;
526 }
527 }
528
529 if(!success) fail(Controller.CPU, "getPerCpuUsage", Arrays.toString(newPerCpu),
530 Arrays.toString(startPerCpu));
531 }
532
533 public void testMemoryUsage() throws Exception {
534 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
535 long memoryMaxUsage = metrics.getMemoryMaxUsage();
536 long memoryUsage = metrics.getMemoryUsage();
537 long newMemoryMaxUsage = 0, newMemoryUsage = 0;
538
539 // allocate memory in a loop and check more than once for new values
540 // otherwise we might see seldom the effect of decreasing new memory values
541 // e.g. because the system could free up memory
542 byte[][] bytes = new byte[32][];
543 for (int i = 0; i < 32; i++) {
544 bytes[i] = new byte[8*1024*1024];
545 newMemoryUsage = metrics.getMemoryUsage();
546 if (newMemoryUsage > memoryUsage) {
547 break;
548 }
549 }
550 newMemoryMaxUsage = metrics.getMemoryMaxUsage();
|
21 * questions.
22 */
23
24 package jdk.test.lib.containers.cgroup;
25
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.Map;
35 import java.util.Scanner;
36 import java.util.Set;
37 import java.util.stream.Collectors;
38 import java.util.stream.LongStream;
39 import java.util.stream.Stream;
40
41 import jdk.internal.platform.CgroupSubsystem;
42 import jdk.internal.platform.CgroupV1Metrics;
43 import jdk.internal.platform.Metrics;
44 import jdk.test.lib.Asserts;
45
46 public class MetricsTesterCgroupV1 implements CgroupMetricsTester {
47
48 // Aliased for readability
49 private static final long RETVAL_UNAVAILABLE = CgroupSubsystem.LONG_RETVAL_UNLIMITED;
50 private static long unlimited_minimum = 0x7FFFFFFFFF000000L;
51 long startSysVal;
52 long startUserVal;
53 long startUsage;
54 long startPerCpu[];
55
56 enum Controller {
57 MEMORY("memory"),
58 CPUSET("cpuset"),
59 CPU("cpu"),
60 CPUACCT("cpuacct"),
61 BLKIO("blkio");
62
63 private String value;
64
65 Controller(String value) {
66 this.value = value;
67 }
68
69 public String value() {
114 private static void createSubsystems(String[] line) {
115 if (line.length < 5) return;
116 Path p = Paths.get(line[4]);
117 String subsystemName = p.getFileName().toString();
118 if (subsystemName != null) {
119 for (String subSystem : subsystemName.split(",")) {
120 if (allowedSubSystems.contains(subSystem)) {
121 subSystemPaths.put(subSystem, new String[]{line[3], line[4]});
122 }
123 }
124 }
125 }
126
127 public void setup() {
128 Metrics metrics = Metrics.systemMetrics();
129 // Initialize CPU usage metrics before we do any testing.
130 startSysVal = metrics.getCpuSystemUsage();
131 startUserVal = metrics.getCpuUserUsage();
132 startUsage = metrics.getCpuUsage();
133 startPerCpu = metrics.getPerCpuUsage();
134
135 try {
136 Stream<String> lines = Files.lines(Paths.get("/proc/self/mountinfo"));
137 lines.filter(line -> line.contains(" - cgroup cgroup "))
138 .map(line -> line.split(" "))
139 .forEach(MetricsTesterCgroupV1::createSubsystems);
140 lines.close();
141
142 lines = Files.lines(Paths.get("/proc/self/cgroup"));
143 lines.map(line -> line.split(":"))
144 .filter(line -> (line.length >= 3))
145 .forEach(MetricsTesterCgroupV1::setPath);
146 lines.close();
147 } catch (IOException e) {
148 }
149 }
150
151 private static String getFileContents(Controller subSystem, String fileName) {
152 String fname = subSystemPaths.get(subSystem.value())[0] + File.separator + fileName;
153 try {
154 return new Scanner(new File(fname)).useDelimiter("\\Z").next();
155 } catch (FileNotFoundException e) {
156 System.err.println("Unable to open : " + fname);
157 return null;
158 }
159 }
160
161 private static long getLongValueFromFile(Controller subSystem, String fileName) {
162 String data = getFileContents(subSystem, fileName);
163 return (data == null || data.isEmpty()) ? RETVAL_UNAVAILABLE : convertStringToLong(data);
164 }
165
166 private static long convertStringToLong(String strval) {
167 return CgroupMetricsTester.convertStringToLong(strval, RETVAL_UNAVAILABLE, Long.MAX_VALUE);
168 }
169
170 private static long getLongValueFromFile(Controller subSystem, String metric, String subMetric) {
171 String stats = getFileContents(subSystem, metric);
172 String[] tokens = stats.split("[\\r\\n]+");
173 for (int i = 0; i < tokens.length; i++) {
174 if (tokens[i].startsWith(subMetric)) {
175 String strval = tokens[i].split("\\s+")[1];
176 return convertStringToLong(strval);
177 }
178 }
179 return RETVAL_UNAVAILABLE;
180 }
181
182 private static double getDoubleValueFromFile(Controller subSystem, String fileName) {
183 String data = getFileContents(subSystem, fileName);
184 return data == null || data.isEmpty() ? RETVAL_UNAVAILABLE : Double.parseDouble(data);
185 }
186
187 private static void fail(Controller system, String metric, long oldVal, long testVal) {
188 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
189 }
190
191 private static void fail(Controller system, String metric, String oldVal, String testVal) {
192 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
193 }
194
195 private static void fail(Controller system, String metric, double oldVal, double testVal) {
196 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
197 }
198
199 private static void fail(Controller system, String metric, boolean oldVal, boolean testVal) {
200 CgroupMetricsTester.fail(system.value, metric, oldVal, testVal);
201 }
202
203 private static void warn(Controller system, String metric, long oldVal, long testVal) {
204 CgroupMetricsTester.warn(system.value, metric, oldVal, testVal);
205 }
206
207 private Long[] boxedArrayOrNull(long[] primitiveArray) {
208 if (primitiveArray == null) {
209 return null;
210 }
211 return LongStream.of(primitiveArray).boxed().toArray(Long[]::new);
212 }
213
214 public void testMemorySubsystem() {
215 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
216
217 // User Memory
218 long oldVal = metrics.getMemoryFailCount();
219 long newVal = getLongValueFromFile(Controller.MEMORY, "memory.failcnt");
220 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
221 fail(Controller.MEMORY, "memory.failcnt", oldVal, newVal);
222 }
223
224 oldVal = metrics.getMemoryLimit();
225 newVal = getLongValueFromFile(Controller.MEMORY, "memory.limit_in_bytes");
226 newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
227 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
228 fail(Controller.MEMORY, "memory.limit_in_bytes", oldVal, newVal);
229 }
230
231 oldVal = metrics.getMemoryMaxUsage();
232 newVal = getLongValueFromFile(Controller.MEMORY, "memory.max_usage_in_bytes");
233 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
234 fail(Controller.MEMORY, "memory.max_usage_in_bytes", oldVal, newVal);
235 }
236
237 oldVal = metrics.getMemoryUsage();
238 newVal = getLongValueFromFile(Controller.MEMORY, "memory.usage_in_bytes");
239 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
240 fail(Controller.MEMORY, "memory.usage_in_bytes", oldVal, newVal);
241 }
242
243 // Kernel memory
244 oldVal = metrics.getKernelMemoryFailCount();
245 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.failcnt");
246 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
247 fail(Controller.MEMORY, "memory.kmem.failcnt", oldVal, newVal);
248 }
249
250 oldVal = metrics.getKernelMemoryLimit();
251 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.limit_in_bytes");
252 newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
253 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
254 fail(Controller.MEMORY, "memory.kmem.limit_in_bytes", oldVal, newVal);
255 }
256
257 oldVal = metrics.getKernelMemoryMaxUsage();
258 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.max_usage_in_bytes");
259 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
260 fail(Controller.MEMORY, "memory.kmem.max_usage_in_bytes", oldVal, newVal);
261 }
262
263 oldVal = metrics.getKernelMemoryUsage();
264 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.usage_in_bytes");
265 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
266 fail(Controller.MEMORY, "memory.kmem.usage_in_bytes", oldVal, newVal);
267 }
268
269 //TCP Memory
270 oldVal = metrics.getTcpMemoryFailCount();
271 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.failcnt");
272 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
273 fail(Controller.MEMORY, "memory.kmem.tcp.failcnt", oldVal, newVal);
274 }
275
276 oldVal = metrics.getTcpMemoryLimit();
277 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes");
278 newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED: newVal;
279 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
280 fail(Controller.MEMORY, "memory.kmem.tcp.limit_in_bytes", oldVal, newVal);
281 }
282
283 oldVal = metrics.getTcpMemoryMaxUsage();
284 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes");
285 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
286 fail(Controller.MEMORY, "memory.kmem.tcp.max_usage_in_bytes", oldVal, newVal);
287 }
288
289 oldVal = metrics.getTcpMemoryUsage();
290 newVal = getLongValueFromFile(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes");
291 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
292 fail(Controller.MEMORY, "memory.kmem.tcp.usage_in_bytes", oldVal, newVal);
293 }
294
295 // Memory and Swap
296 oldVal = metrics.getMemoryAndSwapFailCount();
297 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.failcnt");
298 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
299 fail(Controller.MEMORY, "memory.memsw.failcnt", oldVal, newVal);
300 }
301
302 oldVal = metrics.getMemoryAndSwapLimit();
303 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.limit_in_bytes");
304 newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
305 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
306 fail(Controller.MEMORY, "memory.memsw.limit_in_bytes", oldVal, newVal);
307 }
308
309 oldVal = metrics.getMemoryAndSwapMaxUsage();
310 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.max_usage_in_bytes");
311 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
312 fail(Controller.MEMORY, "memory.memsw.max_usage_in_bytes", oldVal, newVal);
313 }
314
315 oldVal = metrics.getMemoryAndSwapUsage();
316 newVal = getLongValueFromFile(Controller.MEMORY, "memory.memsw.usage_in_bytes");
317 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
318 fail(Controller.MEMORY, "memory.memsw.usage_in_bytes", oldVal, newVal);
319 }
320
321 oldVal = metrics.getMemorySoftLimit();
322 newVal = getLongValueFromFile(Controller.MEMORY, "memory.soft_limit_in_bytes");
323 newVal = newVal > unlimited_minimum ? CgroupSubsystem.LONG_RETVAL_UNLIMITED : newVal;
324 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
325 fail(Controller.MEMORY, "memory.soft_limit_in_bytes", oldVal, newVal);
326 }
327
328 boolean oomKillEnabled = metrics.isMemoryOOMKillEnabled();
329 boolean newOomKillEnabled = getLongValueFromFile(Controller.MEMORY,
330 "memory.oom_control", "oom_kill_disable") == 0L ? true : false;
331 if (oomKillEnabled != newOomKillEnabled) {
332 throw new RuntimeException("Test failed for - " + Controller.MEMORY.value + ":"
333 + "memory.oom_control:oom_kill_disable" + ", expected ["
334 + oomKillEnabled + "], got [" + newOomKillEnabled + "]");
335 }
336 }
337
338 public void testCpuAccounting() {
339 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
340 long oldVal = metrics.getCpuUsage();
341 long newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.usage");
342
343 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
344 warn(Controller.CPUACCT, "cpuacct.usage", oldVal, newVal);
345 }
346
347 String newValsStr = getFileContents(Controller.CPUACCT, "cpuacct.usage_percpu");
348 Long[] newVals = null;
349 if (newValsStr != null) {
350 newVals = Stream.of(newValsStr
351 .split("\\s+"))
352 .map(Long::parseLong)
353 .toArray(Long[]::new);
354 }
355 Long[] oldVals = boxedArrayOrNull(metrics.getPerCpuUsage());
356 if (oldVals != null) {
357 for (int i = 0; i < oldVals.length; i++) {
358 if (!CgroupMetricsTester.compareWithErrorMargin(oldVals[i], newVals[i])) {
359 warn(Controller.CPUACCT, "cpuacct.usage_percpu", oldVals[i], newVals[i]);
360 }
361 }
362 } else {
363 Asserts.assertNull(newVals, Controller.CPUACCT.value() + "cpuacct.usage_percpu not both null");
364 }
365
366 oldVal = metrics.getCpuUserUsage();
367 newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "user");
368 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
369 warn(Controller.CPUACCT, "cpuacct.usage - user", oldVal, newVal);
370 }
371
372 oldVal = metrics.getCpuSystemUsage();
373 newVal = getLongValueFromFile(Controller.CPUACCT, "cpuacct.stat", "system");
374 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
375 warn(Controller.CPUACCT, "cpuacct.usage - system", oldVal, newVal);
376 }
377 }
378
379 public void testCpuSchedulingMetrics() {
380 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
381 long oldVal = metrics.getCpuPeriod();
382 long newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.cfs_period_us");
383 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
384 fail(Controller.CPUACCT, "cpu.cfs_period_us", oldVal, newVal);
401 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_periods");
402 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
403 fail(Controller.CPUACCT, "cpu.stat - nr_periods", oldVal, newVal);
404 }
405
406 oldVal = metrics.getCpuNumThrottled();
407 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "nr_throttled");
408 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
409 fail(Controller.CPUACCT, "cpu.stat - nr_throttled", oldVal, newVal);
410 }
411
412 oldVal = metrics.getCpuThrottledTime();
413 newVal = getLongValueFromFile(Controller.CPUACCT, "cpu.stat", "throttled_time");
414 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
415 fail(Controller.CPUACCT, "cpu.stat - throttled_time", oldVal, newVal);
416 }
417 }
418
419 public void testCpuSets() {
420 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
421 Integer[] oldVal = CgroupMetricsTester.boxedArrayOrNull(metrics.getCpuSetCpus());
422 oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
423
424 String cpusstr = getFileContents(Controller.CPUSET, "cpuset.cpus");
425 // Parse range string in the format 1,2-6,7
426 Integer[] newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
427 newVal = CgroupMetricsTester.sortAllowNull(newVal);
428 if (Arrays.compare(oldVal, newVal) != 0) {
429 fail(Controller.CPUSET, "cpuset.cpus", Arrays.toString(oldVal),
430 Arrays.toString(newVal));
431 }
432
433 int [] cpuSets = metrics.getEffectiveCpuSetCpus();
434
435 oldVal = CgroupMetricsTester.boxedArrayOrNull(cpuSets);
436 oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
437 cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_cpus");
438 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
439 newVal = CgroupMetricsTester.sortAllowNull(newVal);
440 if (Arrays.compare(oldVal, newVal) != 0) {
441 fail(Controller.CPUSET, "cpuset.effective_cpus", Arrays.toString(oldVal),
442 Arrays.toString(newVal));
443 }
444
445 oldVal = CgroupMetricsTester.boxedArrayOrNull(metrics.getCpuSetMems());
446 oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
447 cpusstr = getFileContents(Controller.CPUSET, "cpuset.mems");
448 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
449 newVal = CgroupMetricsTester.sortAllowNull(newVal);
450 if (Arrays.compare(oldVal, newVal) != 0) {
451 fail(Controller.CPUSET, "cpuset.mems", Arrays.toString(oldVal),
452 Arrays.toString(newVal));
453 }
454
455 int [] cpuSetMems = metrics.getEffectiveCpuSetMems();
456
457 oldVal = CgroupMetricsTester.boxedArrayOrNull(cpuSetMems);
458 oldVal = CgroupMetricsTester.sortAllowNull(oldVal);
459 cpusstr = getFileContents(Controller.CPUSET, "cpuset.effective_mems");
460 newVal = CgroupMetricsTester.convertCpuSetsToArray(cpusstr);
461 newVal = CgroupMetricsTester.sortAllowNull(newVal);
462 if (Arrays.compare(oldVal, newVal) != 0) {
463 fail(Controller.CPUSET, "cpuset.effective_mems", Arrays.toString(oldVal),
464 Arrays.toString(newVal));
465 }
466
467 double oldValue = metrics.getCpuSetMemoryPressure();
468 double newValue = getDoubleValueFromFile(Controller.CPUSET, "cpuset.memory_pressure");
469 if (!CgroupMetricsTester.compareWithErrorMargin(oldValue, newValue)) {
470 fail(Controller.CPUSET, "cpuset.memory_pressure", oldValue, newValue);
471 }
472
473 boolean oldV = metrics.isCpuSetMemoryPressureEnabled();
474 boolean newV = getLongValueFromFile(Controller.CPUSET,
475 "cpuset.memory_pressure_enabled") == 1 ? true : false;
476 if (oldV != newV) {
477 fail(Controller.CPUSET, "cpuset.memory_pressure_enabled", oldV, newV);
478 }
479 }
480
481 private void testBlkIO() {
482 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
483 long oldVal = metrics.getBlkIOServiceCount();
484 long newVal = getLongValueFromFile(Controller.BLKIO,
485 "blkio.throttle.io_service_bytes", "Total");
486 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
487 fail(Controller.BLKIO, "blkio.throttle.io_service_bytes - Total",
488 oldVal, newVal);
489 }
490
491 oldVal = metrics.getBlkIOServiced();
492 newVal = getLongValueFromFile(Controller.BLKIO, "blkio.throttle.io_serviced", "Total");
493 if (!CgroupMetricsTester.compareWithErrorMargin(oldVal, newVal)) {
494 fail(Controller.BLKIO, "blkio.throttle.io_serviced - Total", oldVal, newVal);
495 }
496 }
497
498 public void testCpuConsumption() throws IOException, InterruptedException {
499 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
500 // make system call
501 long newSysVal = metrics.getCpuSystemUsage();
502 long newUserVal = metrics.getCpuUserUsage();
503 long newUsage = metrics.getCpuUsage();
504 long[] newPerCpu = metrics.getPerCpuUsage();
505
506 // system/user CPU usage counters may be slowly increasing.
507 // allow for equal values for a pass
508 if (newSysVal < startSysVal) {
509 fail(Controller.CPU, "getCpuSystemUsage", newSysVal, startSysVal);
510 }
511
512 // system/user CPU usage counters may be slowly increasing.
513 // allow for equal values for a pass
514 if (newUserVal < startUserVal) {
515 fail(Controller.CPU, "getCpuUserUsage", newUserVal, startUserVal);
516 }
517
518 if (newUsage <= startUsage) {
519 fail(Controller.CPU, "getCpuUsage", newUsage, startUsage);
520 }
521
522 if (startPerCpu != null) {
523 boolean success = false;
524 for (int i = 0; i < startPerCpu.length; i++) {
525 if (newPerCpu[i] > startPerCpu[i]) {
526 success = true;
527 break;
528 }
529 }
530 if (!success) {
531 fail(Controller.CPU, "getPerCpuUsage", Arrays.toString(newPerCpu),
532 Arrays.toString(startPerCpu));
533 }
534 } else {
535 Asserts.assertNull(newPerCpu, Controller.CPU.value() + " getPerCpuUsage not both null");
536 }
537
538 }
539
540 public void testMemoryUsage() throws Exception {
541 CgroupV1Metrics metrics = (CgroupV1Metrics)Metrics.systemMetrics();
542 long memoryMaxUsage = metrics.getMemoryMaxUsage();
543 long memoryUsage = metrics.getMemoryUsage();
544 long newMemoryMaxUsage = 0, newMemoryUsage = 0;
545
546 // allocate memory in a loop and check more than once for new values
547 // otherwise we might see seldom the effect of decreasing new memory values
548 // e.g. because the system could free up memory
549 byte[][] bytes = new byte[32][];
550 for (int i = 0; i < 32; i++) {
551 bytes[i] = new byte[8*1024*1024];
552 newMemoryUsage = metrics.getMemoryUsage();
553 if (newMemoryUsage > memoryUsage) {
554 break;
555 }
556 }
557 newMemoryMaxUsage = metrics.getMemoryMaxUsage();
|