8197589: Update CPU count algorithm when both cpu shares and quotas are used

Reviewed-by: dholmes, mseledtsov
This commit is contained in:
Bob Vandette 2018-02-23 10:17:35 -05:00
parent 809315bdd1
commit c1359ec107
3 changed files with 69 additions and 31 deletions

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -62,6 +62,11 @@
product(bool, UseContainerSupport, true, \ product(bool, UseContainerSupport, true, \
"Enable detection and runtime container configuration support") \ "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, \ diagnostic(bool, UseCpuAllocPath, false, \
"Use CPU_ALLOC code path in os::active_processor_count ") "Use CPU_ALLOC code path in os::active_processor_count ")

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -499,11 +499,11 @@ jlong OSContainer::memory_max_usage_in_bytes() {
/* active_processor_count /* active_processor_count
* *
* Calculate an appropriate number of active processors for the * 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 affinity
* cpu quota & cpu period * cgroup cpu quota & cpu period
* cpu shares * cgroup cpu shares
* *
* Algorithm: * Algorithm:
* *
@ -513,42 +513,61 @@ jlong OSContainer::memory_max_usage_in_bytes() {
* required CPUs by dividing quota by period. * required CPUs by dividing quota by period.
* *
* If shares are in effect (shares != -1), calculate the number * 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. * by PER_CPU_SHARES.
* *
* All results of division are rounded up to the next whole number. * 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: * return:
* number of cpus * number of CPUs
* OSCONTAINER_ERROR if failure occured during extract of cpuset info
*/ */
int OSContainer::active_processor_count() { int OSContainer::active_processor_count() {
int cpu_count, share_count, quota_count; int quota_count = 0, share_count = 0;
int share, quota, period; int cpu_count, limit_count;
int result; 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 (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;
}
quota = cpu_quota();
period = cpu_period();
if (quota > -1 && period > 0) { if (quota > -1 && period > 0) {
quota_count = ceilf((float)quota / (float)period); quota_count = ceilf((float)quota / (float)period);
log_trace(os, container)("quota_count: %d", quota_count); log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count);
} else { }
quota_count = cpu_count; if (share > -1) {
share_count = ceilf((float)share / (float)PER_CPU_SHARES);
log_trace(os, container)("CPU Share count based on shares: %d", share_count);
} }
result = MIN2(cpu_count, MIN2(share_count, quota_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, limit_count);
log_trace(os, container)("OSContainer::active_processor_count: %d", result); log_trace(os, container)("OSContainer::active_processor_count: %d", result);
return result; return result;
} }

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -94,14 +94,23 @@ public class TestCPUAwareness {
// Test subset of cpuset with one element // Test subset of cpuset with one element
if (cpuSet.size() >= 1) { if (cpuSet.size() >= 1) {
String testCpuSet = CPUSetsReader.listToString(cpuSet, 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 // Test subset of cpuset with two elements
if (cpuSet.size() >= 2) { if (cpuSet.size() >= 2) {
String testCpuSet = CPUSetsReader.listToString(cpuSet, 2); String testCpuSet = CPUSetsReader.listToString(cpuSet, 2);
testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, 2); testAPCCombo(testCpuSet, 200*1000, 100*1000, 4*1024, true, 2);
testAPCCombo(testCpuSet, 200*1000, 100*1000, 1*1024, 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 @@ public class TestCPUAwareness {
// Test correctess of automatically selected active processor cound // Test correctess of automatically selected active processor cound
private static void testAPCCombo(String cpuset, int quota, int period, int shares, 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"); Common.logNewTestCase("test APC Combo");
System.out.println("cpuset = " + cpuset); System.out.println("cpuset = " + cpuset);
System.out.println("quota = " + quota); System.out.println("quota = " + quota);
System.out.println("period = " + period); System.out.println("period = " + period);
System.out.println("shares = " + period); System.out.println("shares = " + period);
System.out.println("usePreferContainerQuotaForCPUCount = " + usePreferContainerQuotaForCPUCount);
System.out.println("expectedAPC = " + expectedAPC); System.out.println("expectedAPC = " + expectedAPC);
expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC); expectedAPC = adjustExpectedAPCForAvailableCPUs(expectedAPC);
@ -174,6 +185,9 @@ public class TestCPUAwareness {
.addDockerOpts("--cpu-period=" + period) .addDockerOpts("--cpu-period=" + period)
.addDockerOpts("--cpu-quota=" + quota) .addDockerOpts("--cpu-quota=" + quota)
.addDockerOpts("--cpu-shares=" + shares); .addDockerOpts("--cpu-shares=" + shares);
if (!usePreferContainerQuotaForCPUCount) opts.addJavaOpts("-XX:-PreferContainerQuotaForCPUCount");
Common.run(opts) Common.run(opts)
.shouldMatch("active_processor_count.*" + expectedAPC); .shouldMatch("active_processor_count.*" + expectedAPC);
} }