test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java
branchJDK-8200758-branch
changeset 57325 e678ef92ef0b
parent 57324 c1d3935fbb79
parent 54527 96d290a7e94f
child 57326 603101a378fe
equal deleted inserted replaced
57324:c1d3935fbb79 57325:e678ef92ef0b
     1 /*
       
     2  * Copyright (c) 2017, 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  */
       
    23 
       
    24 
       
    25 /*
       
    26  * @test
       
    27  * @summary Test JVM's CPU resource awareness when running inside docker container
       
    28  * @requires docker.support
       
    29  * @library /test/lib
       
    30  * @modules java.base/jdk.internal.misc
       
    31  *          java.management
       
    32  *          jdk.jartool/sun.tools.jar
       
    33  * @run driver TestCPUAwareness
       
    34  */
       
    35 import java.util.List;
       
    36 import jdk.test.lib.containers.docker.Common;
       
    37 import jdk.test.lib.containers.docker.DockerRunOptions;
       
    38 import jdk.test.lib.containers.docker.DockerTestUtils;
       
    39 import jdk.test.lib.containers.cgroup.CPUSetsReader;
       
    40 
       
    41 public class TestCPUAwareness {
       
    42     private static final String imageName = Common.imageName("cpu");
       
    43     private static final int availableCPUs = Runtime.getRuntime().availableProcessors();
       
    44 
       
    45     public static void main(String[] args) throws Exception {
       
    46         if (!DockerTestUtils.canTestDocker()) {
       
    47             return;
       
    48         }
       
    49 
       
    50         System.out.println("Test Environment: detected availableCPUs = " + availableCPUs);
       
    51         DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker");
       
    52 
       
    53         try {
       
    54             // cpuset, period, shares, expected Active Processor Count
       
    55             testComboWithCpuSets();
       
    56 
       
    57             // cpu shares - it should be safe to use CPU shares exceeding available CPUs
       
    58             testCpuShares(256, 1);
       
    59             testCpuShares(2048, 2);
       
    60             testCpuShares(4096, 4);
       
    61 
       
    62             // leave one CPU for system and tools, otherwise this test may be unstable
       
    63             int maxNrOfAvailableCpus =  availableCPUs - 1;
       
    64             for (int i=1; i < maxNrOfAvailableCpus; i = i * 2) {
       
    65                 testCpus(i, i);
       
    66             }
       
    67 
       
    68             // If ActiveProcessorCount is set, the VM should use it, regardless of other
       
    69             // container settings, host settings or available CPUs on the host.
       
    70             testActiveProcessorCount(1, 1);
       
    71             testActiveProcessorCount(2, 2);
       
    72 
       
    73             // cpu quota and period
       
    74             testCpuQuotaAndPeriod(50*1000, 100*1000);
       
    75             testCpuQuotaAndPeriod(100*1000, 100*1000);
       
    76             testCpuQuotaAndPeriod(150*1000, 100*1000);
       
    77             testCpuQuotaAndPeriod(400*1000, 100*1000);
       
    78 
       
    79         } finally {
       
    80             DockerTestUtils.removeDockerImage(imageName);
       
    81         }
       
    82     }
       
    83 
       
    84 
       
    85     private static void testComboWithCpuSets() throws Exception {
       
    86         String cpuSetStr = CPUSetsReader.readFromProcStatus("Cpus_allowed_list");
       
    87         System.out.println("cpuSetStr = " + cpuSetStr);
       
    88 
       
    89         if (cpuSetStr == null) {
       
    90             System.out.printf("The cpuset test cases are skipped");
       
    91         } else {
       
    92             List<Integer> cpuSet = CPUSetsReader.parseCpuSet(cpuSetStr);
       
    93 
       
    94             // Test subset of cpuset with one element
       
    95             if (cpuSet.size() >= 1) {
       
    96                 String testCpuSet = CPUSetsReader.listToString(cpuSet, 1);
       
    97                 testAPCCombo(testCpuSet, 200*1000, 100*1000,   4*1024, true, 1);
       
    98             }
       
    99 
       
   100             // Test subset of cpuset with two elements
       
   101             if (cpuSet.size() >= 2) {
       
   102                 String testCpuSet = CPUSetsReader.listToString(cpuSet, 2);
       
   103                 testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 2);
       
   104                 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023,   true, 2);
       
   105                 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023,   false,  1);
       
   106             }
       
   107 
       
   108             // Test subset of cpuset with three elements
       
   109             if (cpuSet.size() >= 3) {
       
   110                 String testCpuSet = CPUSetsReader.listToString(cpuSet, 3);
       
   111                 testAPCCombo(testCpuSet, 100*1000, 100*1000, 2*1024, true, 1);
       
   112                 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023,   true, 2);
       
   113                 testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023,   false,  1);
       
   114             }
       
   115         }
       
   116     }
       
   117 
       
   118 
       
   119     private static void testActiveProcessorCount(int valueToSet, int expectedValue) throws Exception {
       
   120         Common.logNewTestCase("Test ActiveProcessorCount: valueToSet = " + valueToSet);
       
   121 
       
   122         DockerRunOptions opts = Common.newOpts(imageName)
       
   123             .addJavaOpts("-XX:ActiveProcessorCount=" + valueToSet, "-Xlog:os=trace");
       
   124         Common.run(opts)
       
   125             .shouldMatch("active processor count set by user.*" + expectedValue);
       
   126     }
       
   127 
       
   128 
       
   129     private static void testCpus(int valueToSet, int expectedTraceValue) throws Exception {
       
   130         Common.logNewTestCase("test cpus: " + valueToSet);
       
   131         DockerRunOptions opts = Common.newOpts(imageName)
       
   132             .addDockerOpts("--cpu-period=" + 10000)
       
   133             .addDockerOpts("--cpu-quota=" + valueToSet * 10000);
       
   134         Common.run(opts)
       
   135             .shouldMatch("active_processor_count.*" + expectedTraceValue);
       
   136     }
       
   137 
       
   138 
       
   139     // Expected active processor count can not exceed available CPU count
       
   140     private static int adjustExpectedAPCForAvailableCPUs(int expectedAPC) {
       
   141         if (expectedAPC > availableCPUs) {
       
   142             expectedAPC = availableCPUs;
       
   143             System.out.println("Adjusted expectedAPC = " + expectedAPC);
       
   144         }
       
   145         return expectedAPC;
       
   146     }
       
   147 
       
   148 
       
   149     private static void testCpuQuotaAndPeriod(int quota, int period)
       
   150         throws Exception {
       
   151         Common.logNewTestCase("test cpu quota and period: ");
       
   152         System.out.println("quota = " + quota);
       
   153         System.out.println("period = " + period);
       
   154 
       
   155         int expectedAPC = (int) Math.ceil((float) quota / (float) period);
       
   156         System.out.println("expectedAPC = " + expectedAPC);
       
   157         expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
       
   158 
       
   159         DockerRunOptions opts = Common.newOpts(imageName)
       
   160             .addDockerOpts("--cpu-period=" + period)
       
   161             .addDockerOpts("--cpu-quota=" + quota);
       
   162 
       
   163         Common.run(opts)
       
   164             .shouldMatch("CPU Period is.*" + period)
       
   165             .shouldMatch("CPU Quota is.*" + quota)
       
   166             .shouldMatch("active_processor_count.*" + expectedAPC);
       
   167     }
       
   168 
       
   169 
       
   170     // Test correctess of automatically selected active processor cound
       
   171     private static void testAPCCombo(String cpuset, int quota, int period, int shares,
       
   172                                      boolean usePreferContainerQuotaForCPUCount,
       
   173                                      int expectedAPC) throws Exception {
       
   174         Common.logNewTestCase("test APC Combo");
       
   175         System.out.println("cpuset = " + cpuset);
       
   176         System.out.println("quota = " + quota);
       
   177         System.out.println("period = " + period);
       
   178         System.out.println("shares = " + shares);
       
   179         System.out.println("usePreferContainerQuotaForCPUCount = " + usePreferContainerQuotaForCPUCount);
       
   180         System.out.println("expectedAPC = " + expectedAPC);
       
   181 
       
   182         expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
       
   183 
       
   184         DockerRunOptions opts = Common.newOpts(imageName)
       
   185             .addDockerOpts("--cpuset-cpus", "" + cpuset)
       
   186             .addDockerOpts("--cpu-period=" + period)
       
   187             .addDockerOpts("--cpu-quota=" + quota)
       
   188             .addDockerOpts("--cpu-shares=" + shares);
       
   189 
       
   190         if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount");
       
   191 
       
   192         Common.run(opts)
       
   193             .shouldMatch("active_processor_count.*" + expectedAPC);
       
   194     }
       
   195 
       
   196 
       
   197     private static void testCpuShares(int shares, int expectedAPC) throws Exception {
       
   198         Common.logNewTestCase("test cpu shares, shares = " + shares);
       
   199         System.out.println("expectedAPC = " + expectedAPC);
       
   200 
       
   201         expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
       
   202 
       
   203         DockerRunOptions opts = Common.newOpts(imageName)
       
   204             .addDockerOpts("--cpu-shares=" + shares);
       
   205         Common.run(opts)
       
   206             .shouldMatch("CPU Shares is.*" + shares)
       
   207             .shouldMatch("active_processor_count.*" + expectedAPC);
       
   208     }
       
   209 }