mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8129937: compiler/codecache/jmx/UsageThresholdIncreasedTest.java fails with "Usage threshold was hit"
Tests should not assume that usage of non-profiled code heap is predictable. Reviewed-by: kvn, dpochepk
This commit is contained in:
parent
4a826139e3
commit
fba308328b
8 changed files with 64 additions and 56 deletions
|
@ -21,6 +21,7 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
import jdk.test.lib.Utils;
|
import jdk.test.lib.Utils;
|
||||||
import java.lang.management.MemoryPoolMXBean;
|
import java.lang.management.MemoryPoolMXBean;
|
||||||
import javax.management.Notification;
|
import javax.management.Notification;
|
||||||
|
@ -80,19 +81,42 @@ public final class CodeCacheUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "non-nmethods" code heap is used by interpreter during bytecode
|
* Checks if the usage of the code heap corresponding to 'btype' can be
|
||||||
* execution, thus, it can't be predicted if this code heap usage will be
|
* predicted at runtime if we disable compilation. The usage of the
|
||||||
* increased or not. Same goes for 'All'.
|
* 'NonNMethod' code heap can not be predicted because we generate adapters
|
||||||
|
* and buffers at runtime. The 'MethodNonProfiled' code heap is also not
|
||||||
|
* predictable because we may generate compiled versions of method handle
|
||||||
|
* intrinsics while resolving methods at runtime. Same applies to 'All'.
|
||||||
*
|
*
|
||||||
* @param btype BlobType to be checked
|
* @param btype BlobType to be checked
|
||||||
* @return boolean value, true if respective code heap is predictable
|
* @return boolean value, true if respective code heap is predictable
|
||||||
*/
|
*/
|
||||||
public static boolean isCodeHeapPredictable(BlobType btype) {
|
public static boolean isCodeHeapPredictable(BlobType btype) {
|
||||||
return btype == BlobType.MethodNonProfiled
|
return btype == BlobType.MethodProfiled;
|
||||||
|| btype == BlobType.MethodProfiled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disableCollectionUsageThresholds(){
|
/**
|
||||||
|
* Verifies that 'newValue' is equal to 'oldValue' if usage of the
|
||||||
|
* corresponding code heap is predictable. Checks the weaker condition
|
||||||
|
* 'newValue >= oldValue' if usage is not predictable because intermediate
|
||||||
|
* allocations may happen.
|
||||||
|
*
|
||||||
|
* @param btype BlobType of the code heap to be checked
|
||||||
|
* @param newValue New value to be verified
|
||||||
|
* @param oldValue Old value to be verified
|
||||||
|
* @param msg Error message if verification fails
|
||||||
|
*/
|
||||||
|
public static void assertEQorGTE(BlobType btype, long newValue, long oldValue, String msg) {
|
||||||
|
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
||||||
|
// Usage is predictable, check strong == condition
|
||||||
|
Asserts.assertEQ(newValue, oldValue, msg);
|
||||||
|
} else {
|
||||||
|
// Usage is not predictable, check weaker >= condition
|
||||||
|
Asserts.assertGTE(newValue, oldValue, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disableCollectionUsageThresholds() {
|
||||||
BlobType.getAvailable().stream()
|
BlobType.getAvailable().stream()
|
||||||
.map(BlobType::getMemoryPool)
|
.map(BlobType::getMemoryPool)
|
||||||
.filter(MemoryPoolMXBean::isCollectionUsageThresholdSupported)
|
.filter(MemoryPoolMXBean::isCollectionUsageThresholdSupported)
|
||||||
|
|
|
@ -52,10 +52,8 @@ public class GetUsageTest {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
for (BlobType btype : BlobType.getAvailable()) {
|
for (BlobType btype : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
for (int allocSize = 10; allocSize < 100000; allocSize *= 10) {
|
||||||
for (int allocSize = 10; allocSize < 100000; allocSize *= 10) {
|
new GetUsageTest(btype, allocSize).runTest();
|
||||||
new GetUsageTest(btype, allocSize).runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,13 +85,15 @@ public class GetUsageTest {
|
||||||
for (MemoryPoolMXBean entry : predictableBeans) {
|
for (MemoryPoolMXBean entry : predictableBeans) {
|
||||||
long diff = current.get(entry) - initial.get(entry);
|
long diff = current.get(entry) - initial.get(entry);
|
||||||
if (entry.equals(btype.getMemoryPool())) {
|
if (entry.equals(btype.getMemoryPool())) {
|
||||||
Asserts.assertFalse(diff <= 0L || diff > usageUpperEstimate,
|
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
||||||
String.format("Pool %s usage increase was reported "
|
Asserts.assertFalse(diff <= 0L || diff > usageUpperEstimate,
|
||||||
+ "unexpectedly as increased by %d using "
|
String.format("Pool %s usage increase was reported "
|
||||||
+ "allocation size %d", entry.getName(),
|
+ "unexpectedly as increased by %d using "
|
||||||
diff, allocateSize));
|
+ "allocation size %d", entry.getName(),
|
||||||
|
diff, allocateSize));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Asserts.assertEQ(diff, 0L,
|
CodeCacheUtils.assertEQorGTE(btype, diff, 0L,
|
||||||
String.format("Pool %s usage changed unexpectedly while"
|
String.format("Pool %s usage changed unexpectedly while"
|
||||||
+ " trying to increase: %s using allocation "
|
+ " trying to increase: %s using allocation "
|
||||||
+ "size %d", entry.getName(),
|
+ "size %d", entry.getName(),
|
||||||
|
|
|
@ -52,9 +52,7 @@ public class PeakUsageTest {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (BlobType btype : BlobType.getAvailable()) {
|
for (BlobType btype : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
new PeakUsageTest(btype).runTest();
|
||||||
new PeakUsageTest(btype).runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@ public class PeakUsageTest {
|
||||||
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
|
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
|
||||||
long newPeakUsage = bean.getPeakUsage().getUsed();
|
long newPeakUsage = bean.getPeakUsage().getUsed();
|
||||||
try {
|
try {
|
||||||
Asserts.assertEQ(newPeakUsage, bean.getUsage().getUsed(),
|
CodeCacheUtils.assertEQorGTE(btype, newPeakUsage, bean.getUsage().getUsed(),
|
||||||
"Peak usage does not match usage after allocation for "
|
"Peak usage does not match usage after allocation for "
|
||||||
+ bean.getName());
|
+ bean.getName());
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -73,18 +71,18 @@ public class PeakUsageTest {
|
||||||
CodeCacheUtils.WB.freeCodeBlob(addr);
|
CodeCacheUtils.WB.freeCodeBlob(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Asserts.assertEQ(newPeakUsage, bean.getPeakUsage().getUsed(),
|
CodeCacheUtils.assertEQorGTE(btype, newPeakUsage, bean.getPeakUsage().getUsed(),
|
||||||
"Code cache peak usage has changed after usage decreased for "
|
"Code cache peak usage has changed after usage decreased for "
|
||||||
+ bean.getName());
|
+ bean.getName());
|
||||||
bean.resetPeakUsage();
|
bean.resetPeakUsage();
|
||||||
Asserts.assertEQ(bean.getPeakUsage().getUsed(),
|
CodeCacheUtils.assertEQorGTE(btype, bean.getPeakUsage().getUsed(),
|
||||||
bean.getUsage().getUsed(),
|
bean.getUsage().getUsed(),
|
||||||
"Code cache peak usage is not equal to usage after reset for "
|
"Code cache peak usage is not equal to usage after reset for "
|
||||||
+ bean.getName());
|
+ bean.getName());
|
||||||
long addr2 = CodeCacheUtils.WB.allocateCodeBlob(
|
long addr2 = CodeCacheUtils.WB.allocateCodeBlob(
|
||||||
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
|
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
|
||||||
try {
|
try {
|
||||||
Asserts.assertEQ(bean.getPeakUsage().getUsed(),
|
CodeCacheUtils.assertEQorGTE(btype, bean.getPeakUsage().getUsed(),
|
||||||
bean.getUsage().getUsed(),
|
bean.getUsage().getUsed(),
|
||||||
"Code cache peak usage is not equal to usage after fresh "
|
"Code cache peak usage is not equal to usage after fresh "
|
||||||
+ "allocation for " + bean.getName());
|
+ "allocation for " + bean.getName());
|
||||||
|
|
|
@ -97,13 +97,11 @@ public class PoolsIndependenceTest implements NotificationListener {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
for (BlobType bt : BlobType.getAvailable()) {
|
for (BlobType bt : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(bt)) {
|
int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0;
|
||||||
int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0;
|
CodeCacheUtils.assertEQorGTE(btype, counters.get(bt.getMemoryPool().getName()).get(),
|
||||||
Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(),
|
expectedNotificationsAmount, String.format("Unexpected "
|
||||||
expectedNotificationsAmount, String.format("Unexpected "
|
+ "amount of notifications for pool: %s",
|
||||||
+ "amount of notifications for pool: %s",
|
bt.getMemoryPool().getName()));
|
||||||
bt.getMemoryPool().getName()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
|
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
|
||||||
|
|
|
@ -54,9 +54,7 @@ public class ThresholdNotificationsTest implements NotificationListener {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (BlobType bt : BlobType.getAvailable()) {
|
for (BlobType bt : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(bt)) {
|
new ThresholdNotificationsTest(bt).runTest();
|
||||||
new ThresholdNotificationsTest(bt).runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +90,9 @@ public class ThresholdNotificationsTest implements NotificationListener {
|
||||||
}
|
}
|
||||||
Asserts.assertTrue(
|
Asserts.assertTrue(
|
||||||
Utils.waitForCondition(
|
Utils.waitForCondition(
|
||||||
() -> counter == iterationsCount, WAIT_TIME),
|
() -> (CodeCacheUtils.isCodeHeapPredictable(btype) ?
|
||||||
|
(counter == iterationsCount) : (counter >= iterationsCount)),
|
||||||
|
WAIT_TIME),
|
||||||
"Couldn't receive expected notifications count");
|
"Couldn't receive expected notifications count");
|
||||||
try {
|
try {
|
||||||
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
|
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
|
||||||
|
|
|
@ -51,13 +51,9 @@ public class UsageThresholdExceededTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
int iterationsCount =
|
int iterationsCount = Integer.getInteger("jdk.test.lib.iterations", 1);
|
||||||
Integer.getInteger("jdk.test.lib.iterations", 1);
|
|
||||||
for (BlobType btype : BlobType.getAvailable()) {
|
for (BlobType btype : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
new UsageThresholdExceededTest(btype, iterationsCount).runTest();
|
||||||
new UsageThresholdExceededTest(btype, iterationsCount)
|
|
||||||
.runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +63,8 @@ public class UsageThresholdExceededTest {
|
||||||
for (int i = 0; i < iterations; i++) {
|
for (int i = 0; i < iterations; i++) {
|
||||||
CodeCacheUtils.hitUsageThreshold(bean, btype);
|
CodeCacheUtils.hitUsageThreshold(bean, btype);
|
||||||
}
|
}
|
||||||
Asserts.assertEQ(bean.getUsageThresholdCount(), oldValue + iterations,
|
CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), oldValue + iterations,
|
||||||
"Unexpected threshold usage count");
|
"Unexpected threshold usage count");
|
||||||
System.out.printf("INFO: Scenario finished successfully for %s%n",
|
System.out.printf("INFO: Scenario finished successfully for %s%n", bean.getName());
|
||||||
bean.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import sun.hotspot.code.BlobType;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test UsageThresholdIncreasedTest
|
* @test UsageThresholdIncreasedTest
|
||||||
* @ignore 8129937
|
|
||||||
* @library /testlibrary /../../test/lib
|
* @library /testlibrary /../../test/lib
|
||||||
* @modules java.base/sun.misc
|
* @modules java.base/sun.misc
|
||||||
* java.management
|
* java.management
|
||||||
|
@ -54,14 +53,12 @@ public class UsageThresholdIncreasedTest {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (BlobType btype : BlobType.getAvailable()) {
|
for (BlobType btype : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
new UsageThresholdIncreasedTest(btype).runTest();
|
||||||
new UsageThresholdIncreasedTest(btype).runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkUsageThresholdCount(MemoryPoolMXBean bean, long count){
|
private void checkUsageThresholdCount(MemoryPoolMXBean bean, long count){
|
||||||
Asserts.assertEQ(bean.getUsageThresholdCount(), count,
|
CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), count,
|
||||||
String.format("Usage threshold was hit: %d times for %s "
|
String.format("Usage threshold was hit: %d times for %s "
|
||||||
+ "Threshold value: %d with current usage: %d",
|
+ "Threshold value: %d with current usage: %d",
|
||||||
bean.getUsageThresholdCount(), bean.getName(),
|
bean.getUsageThresholdCount(), bean.getName(),
|
||||||
|
|
|
@ -50,9 +50,7 @@ public class UsageThresholdNotExceededTest {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (BlobType btype : BlobType.getAvailable()) {
|
for (BlobType btype : BlobType.getAvailable()) {
|
||||||
if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
|
new UsageThresholdNotExceededTest(btype).runTest();
|
||||||
new UsageThresholdNotExceededTest(btype).runTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,13 +63,11 @@ public class UsageThresholdNotExceededTest {
|
||||||
- CodeCacheUtils.getHeaderSize(btype), btype.id);
|
- CodeCacheUtils.getHeaderSize(btype), btype.id);
|
||||||
// a gc cycle triggers usage threshold recalculation
|
// a gc cycle triggers usage threshold recalculation
|
||||||
CodeCacheUtils.WB.fullGC();
|
CodeCacheUtils.WB.fullGC();
|
||||||
Asserts.assertEQ(bean.getUsageThresholdCount(), initialThresholdCount,
|
CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), initialThresholdCount,
|
||||||
String.format("Usage threshold was hit: %d times for %s. "
|
String.format("Usage threshold was hit: %d times for %s. "
|
||||||
+ "Threshold value: %d with current usage: %d",
|
+ "Threshold value: %d with current usage: %d",
|
||||||
bean.getUsageThresholdCount(), bean.getName(),
|
bean.getUsageThresholdCount(), bean.getName(),
|
||||||
bean.getUsageThreshold(), bean.getUsage().getUsed()));
|
bean.getUsageThreshold(), bean.getUsage().getUsed()));
|
||||||
|
System.out.println("INFO: Case finished successfully for " + bean.getName());
|
||||||
System.out.println("INFO: Case finished successfully for "
|
|
||||||
+ bean.getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue