Thu, 31 Jan 2019 23:56:37 +0800
8217597: [TESTBUG] old version docker does not support --cpus
Summary: "--cpus" is only available in Docker 1.13 and higher, and is the equivalent of setting both --cpu-period and --cpu-quota.
Reviewed-by: bobv, dholmes
Contributed-by: aoqi@loongson.cn
1 /*
2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
25 /*
26 * @test
27 * @summary Test JVM's CPU resource awareness when running inside docker container
28 * @library /testlibrary
29 * @run driver TestCPUAwareness
30 */
32 import java.util.List;
33 import com.oracle.java.testlibrary.Common;
34 import com.oracle.java.testlibrary.DockerTestUtils;
35 import com.oracle.java.testlibrary.DockerRunOptions;
37 public class TestCPUAwareness {
38 private static final String imageName = Common.imageName("cpu");
39 private static final int availableCPUs = Runtime.getRuntime().availableProcessors();
41 public static void main(String[] args) throws Exception {
42 if (!DockerTestUtils.canTestDocker()) {
43 return;
44 }
46 System.out.println("Test Environment: detected availableCPUs = " + availableCPUs);
47 DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
49 try {
50 // cpuset, period, shares, expected Active Processor Count
51 testComboWithCpuSets();
53 // cpu shares - it should be safe to use CPU shares exceeding available CPUs
54 testCpuShares(256, 1);
55 testCpuShares(2048, 2);
56 testCpuShares(4096, 4);
58 // leave one CPU for system and tools, otherwise this test may be unstable
59 int maxNrOfAvailableCpus = availableCPUs - 1;
60 for (int i=1; i < maxNrOfAvailableCpus; i = i * 2) {
61 testCpus(i, i);
62 }
64 // If ActiveProcessorCount is set, the VM should use it, regardless of other
65 // container settings, host settings or available CPUs on the host.
66 testActiveProcessorCount(1, 1);
67 testActiveProcessorCount(2, 2);
69 // cpu quota and period
70 testCpuQuotaAndPeriod(50*1000, 100*1000);
71 testCpuQuotaAndPeriod(100*1000, 100*1000);
72 testCpuQuotaAndPeriod(150*1000, 100*1000);
73 testCpuQuotaAndPeriod(400*1000, 100*1000);
75 } finally {
76 DockerTestUtils.removeDockerImage(imageName);
77 }
78 }
81 private static void testComboWithCpuSets() throws Exception {
82 String cpuSetStr = CPUSetsReader.readFromProcStatus("Cpus_allowed_list");
83 System.out.println("cpuSetStr = " + cpuSetStr);
85 if (cpuSetStr == null) {
86 System.out.printf("The cpuset test cases are skipped");
87 } else {
88 List<Integer> cpuSet = CPUSetsReader.parseCpuSet(cpuSetStr);
90 // Test subset of cpuset with one element
91 if (cpuSet.size() >= 1) {
92 String testCpuSet = CPUSetsReader.listToString(cpuSet, 1);
93 testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 1);
94 }
96 // Test subset of cpuset with two elements
97 if (cpuSet.size() >= 2) {
98 String testCpuSet = CPUSetsReader.listToString(cpuSet, 2);
99 testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 2);
100 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2);
101 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1);
102 }
104 // Test subset of cpuset with three elements
105 if (cpuSet.size() >= 3) {
106 String testCpuSet = CPUSetsReader.listToString(cpuSet, 3);
107 testAPCCombo(testCpuSet, 100*1000, 100*1000, 2*1024, true, 1);
108 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2);
109 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1);
110 }
111 }
112 }
115 private static void testActiveProcessorCount(int valueToSet, int expectedValue) throws Exception {
116 Common.logNewTestCase("Test ActiveProcessorCount: valueToSet = " + valueToSet);
118 DockerRunOptions opts = Common.newOpts(imageName)
119 .addJavaOpts("-XX:ActiveProcessorCount=" + valueToSet, "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintActiveCpus");
120 Common.run(opts)
121 .shouldMatch("active processor count set by user.*" + expectedValue);
122 }
125 private static void testCpus(int valueToSet, int expectedTraceValue) throws Exception {
126 Common.logNewTestCase("test cpus: " + valueToSet);
127 DockerRunOptions opts = Common.newOpts(imageName)
128 .addDockerOpts("--cpu-period=" + 10000)
129 .addDockerOpts("--cpu-quota=" + valueToSet * 10000);
130 Common.run(opts)
131 .shouldMatch("active_processor_count.*" + expectedTraceValue);
132 }
135 // Expected active processor count can not exceed available CPU count
136 private static int adjustExpectedAPCForAvailableCPUs(int expectedAPC) {
137 if (expectedAPC > availableCPUs) {
138 expectedAPC = availableCPUs;
139 System.out.println("Adjusted expectedAPC = " + expectedAPC);
140 }
141 return expectedAPC;
142 }
145 private static void testCpuQuotaAndPeriod(int quota, int period)
146 throws Exception {
147 Common.logNewTestCase("test cpu quota and period: ");
148 System.out.println("quota = " + quota);
149 System.out.println("period = " + period);
151 int expectedAPC = (int) Math.ceil((float) quota / (float) period);
152 System.out.println("expectedAPC = " + expectedAPC);
153 expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
155 DockerRunOptions opts = Common.newOpts(imageName)
156 .addDockerOpts("--cpu-period=" + period)
157 .addDockerOpts("--cpu-quota=" + quota);
159 Common.run(opts)
160 .shouldMatch("CPU Period is.*" + period)
161 .shouldMatch("CPU Quota is.*" + quota)
162 .shouldMatch("active_processor_count.*" + expectedAPC);
163 }
166 // Test correctess of automatically selected active processor cound
167 private static void testAPCCombo(String cpuset, int quota, int period, int shares,
168 boolean usePreferContainerQuotaForCPUCount,
169 int expectedAPC) throws Exception {
170 Common.logNewTestCase("test APC Combo");
171 System.out.println("cpuset = " + cpuset);
172 System.out.println("quota = " + quota);
173 System.out.println("period = " + period);
174 System.out.println("shares = " + period);
175 System.out.println("usePreferContainerQuotaForCPUCount = " + usePreferContainerQuotaForCPUCount);
176 System.out.println("expectedAPC = " + expectedAPC);
178 expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
180 DockerRunOptions opts = Common.newOpts(imageName)
181 .addDockerOpts("--cpuset-cpus", "" + cpuset)
182 .addDockerOpts("--cpu-period=" + period)
183 .addDockerOpts("--cpu-quota=" + quota)
184 .addDockerOpts("--cpu-shares=" + shares);
186 if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount");
188 Common.run(opts)
189 .shouldMatch("active_processor_count.*" + expectedAPC);
190 }
193 private static void testCpuShares(int shares, int expectedAPC) throws Exception {
194 Common.logNewTestCase("test cpu shares, shares = " + shares);
195 System.out.println("expectedAPC = " + expectedAPC);
197 expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
199 DockerRunOptions opts = Common.newOpts(imageName)
200 .addDockerOpts("--cpu-shares=" + shares);
201 Common.run(opts)
202 .shouldMatch("CPU Shares is.*" + shares)
203 .shouldMatch("active_processor_count.*" + expectedAPC);
204 }
205 }