# HG changeset patch # User bobv # Date 1519399055 18000 # Node ID 15765495db120f7d87186d5bfa1ff869529717d9 # Parent 91ada5977172b6c0097efd37da176fa82ef78fe6 8197589: Update CPU count algorithm when both cpu shares and quotas are used Reviewed-by: dholmes, mseledtsov diff -r 91ada5977172 -r 15765495db12 src/hotspot/os/linux/globals_linux.hpp --- a/src/hotspot/os/linux/globals_linux.hpp Fri Feb 23 07:47:29 2018 -0500 +++ b/src/hotspot/os/linux/globals_linux.hpp Fri Feb 23 10:17:35 2018 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,11 @@ product(bool, UseContainerSupport, true, \ "Enable detection and runtime container configuration support") \ \ + product(bool, PreferContainerQuotaForCPUCount, true, \ + "Calculate the container CPU availability based on the value" \ + " of quotas (if set), when true. Otherwise, use the CPU" \ + " shares value, provided it is less than quota.") \ + \ diagnostic(bool, UseCpuAllocPath, false, \ "Use CPU_ALLOC code path in os::active_processor_count ") diff -r 91ada5977172 -r 15765495db12 src/hotspot/os/linux/osContainer_linux.cpp --- a/src/hotspot/os/linux/osContainer_linux.cpp Fri Feb 23 07:47:29 2018 -0500 +++ b/src/hotspot/os/linux/osContainer_linux.cpp Fri Feb 23 10:17:35 2018 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -499,11 +499,11 @@ /* active_processor_count * * Calculate an appropriate number of active processors for the - * VM to use based on these three cgroup options. + * VM to use based on these three inputs. * * cpu affinity - * cpu quota & cpu period - * cpu shares + * cgroup cpu quota & cpu period + * cgroup cpu shares * * Algorithm: * @@ -513,42 +513,61 @@ * required CPUs by dividing quota by period. * * If shares are in effect (shares != -1), calculate the number - * of cpus required for the shares by dividing the share value + * of CPUs required for the shares by dividing the share value * by PER_CPU_SHARES. * * All results of division are rounded up to the next whole number. * - * Return the smaller number from the three different settings. + * If neither shares or quotas have been specified, return the + * number of active processors in the system. + * + * If both shares and quotas have been specified, the results are + * based on the flag PreferContainerQuotaForCPUCount. If true, + * return the quota value. If false return the smallest value + * between shares or quotas. + * + * If shares and/or quotas have been specified, the resulting number + * returned will never exceed the number of active processors. * * return: - * number of cpus - * OSCONTAINER_ERROR if failure occured during extract of cpuset info + * number of CPUs */ int OSContainer::active_processor_count() { - int cpu_count, share_count, quota_count; - int share, quota, period; + int quota_count = 0, share_count = 0; + int cpu_count, limit_count; int result; - cpu_count = os::Linux::active_processor_count(); + cpu_count = limit_count = os::Linux::active_processor_count(); + int quota = cpu_quota(); + int period = cpu_period(); + int share = cpu_shares(); - share = cpu_shares(); + if (quota > -1 && period > 0) { + quota_count = ceilf((float)quota / (float)period); + log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count); + } if (share > -1) { share_count = ceilf((float)share / (float)PER_CPU_SHARES); - log_trace(os, container)("cpu_share count: %d", share_count); - } else { - share_count = cpu_count; + log_trace(os, container)("CPU Share count based on shares: %d", share_count); } - quota = cpu_quota(); - period = cpu_period(); - if (quota > -1 && period > 0) { - quota_count = ceilf((float)quota / (float)period); - log_trace(os, container)("quota_count: %d", quota_count); - } else { - quota_count = cpu_count; + // If both shares and quotas are setup results depend + // on flag PreferContainerQuotaForCPUCount. + // If true, limit CPU count to quota + // If false, use minimum of shares and quotas + if (quota_count !=0 && share_count != 0) { + if (PreferContainerQuotaForCPUCount) { + limit_count = quota_count; + } else { + limit_count = MIN2(quota_count, share_count); + } + } else if (quota_count != 0) { + limit_count = quota_count; + } else if (share_count != 0) { + limit_count = share_count; } - result = MIN2(cpu_count, MIN2(share_count, quota_count)); + result = MIN2(cpu_count, limit_count); log_trace(os, container)("OSContainer::active_processor_count: %d", result); return result; } diff -r 91ada5977172 -r 15765495db12 test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java --- a/test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java Fri Feb 23 07:47:29 2018 -0500 +++ b/test/hotspot/jtreg/runtime/containers/docker/TestCPUAwareness.java Fri Feb 23 10:17:35 2018 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -94,14 +94,23 @@ // Test subset of cpuset with one element if (cpuSet.size() >= 1) { String testCpuSet = CPUSetsReader.listToString(cpuSet, 1); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, 1); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 1); } // Test subset of cpuset with two elements if (cpuSet.size() >= 2) { String testCpuSet = CPUSetsReader.listToString(cpuSet, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, 2); - testAPCCombo(testCpuSet, 200*1000, 100*1000, 1*1024, 2); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 2); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1); + } + + // Test subset of cpuset with three elements + if (cpuSet.size() >= 3) { + String testCpuSet = CPUSetsReader.listToString(cpuSet, 3); + testAPCCombo(testCpuSet, 100*1000, 100*1000, 2*1024, true, 1); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, true, 2); + testAPCCombo(testCpuSet, 200*1000, 100*1000, 1023, false, 1); } } } @@ -159,12 +168,14 @@ // Test correctess of automatically selected active processor cound private static void testAPCCombo(String cpuset, int quota, int period, int shares, - int expectedAPC) throws Exception { + boolean usePreferContainerQuotaForCPUCount, + int expectedAPC) throws Exception { Common.logNewTestCase("test APC Combo"); System.out.println("cpuset = " + cpuset); System.out.println("quota = " + quota); System.out.println("period = " + period); System.out.println("shares = " + period); + System.out.println("usePreferContainerQuotaForCPUCount = " + usePreferContainerQuotaForCPUCount); System.out.println("expectedAPC = " + expectedAPC); expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC); @@ -174,6 +185,9 @@ .addDockerOpts("--cpu-period=" + period) .addDockerOpts("--cpu-quota=" + quota) .addDockerOpts("--cpu-shares=" + shares); + + if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount"); + Common.run(opts) .shouldMatch("active_processor_count.*" + expectedAPC); }