test/runtime/containers/docker/TestCPUAwareness.java

Thu, 31 Jan 2019 23:56:37 +0800

author
aoqi
date
Thu, 31 Jan 2019 23:56:37 +0800
changeset 9657
71aba4a921a0
parent 9421
6cfec782c42c
child 9992
1d9ed8dec94c
permissions
-rw-r--r--

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 }

mercurial