Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8277893: Arraycopy stress tests #6594

Closed
wants to merge 15 commits into from
Closed
@@ -122,6 +122,7 @@ tier1_compiler_1 = \
compiler/blackhole/ \
compiler/c1/ \
compiler/c2/ \
-compiler/arraycopy/stress \
-compiler/c2/Test6850611.java \
-compiler/c2/cr6890943/Test6890943.java \
-compiler/c2/Test6905845.java \
@@ -176,6 +177,11 @@ tier1_compiler_3 = \
tier1_compiler_not_xcomp = \
compiler/profiling

tier2_compiler =

tier3_compiler = \
compiler/arraycopy/stress
shipilev marked this conversation as resolved.
Show resolved Hide resolved

ctw_1 = \
applications/ctw/modules/ \
-:ctw_2 \
@@ -467,11 +473,13 @@ tier2 = \
:hotspot_tier2_runtime \
:hotspot_tier2_runtime_platform_agnostic \
:hotspot_tier2_serviceability \
:tier2_compiler \
:tier2_gc_epsilon \
:tier2_gc_shenandoah

tier3 = \
:hotspot_tier3_runtime \
:tier3_compiler \
:tier3_gc_shenandoah

# Everything that is not in other tiers, but not apps
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/


import java.util.Random;
import jdk.test.lib.Utils;

public abstract class AbstractStressArrayCopy {
/**
* Max array size to test.
*/
static final int MAX_SIZE = 1024*1024 + 1;

/**
* Arrays up to this size would be tested exhaustively: with all combinations
* of source/destination starts and copy lengths. Exercise restraint when bumping
* this value, as the test costs are proportional to N^3 of this setting.
*/
static final int EXHAUSTIVE_SIZES = Integer.getInteger("exhaustiveSizes", 192);

/*
* Larger arrays would fuzzed with this many attempts.
*/
static final int FUZZ_COUNT = Integer.getInteger("fuzzCount", 300);

public static void throwSeedError(int len, int pos) {
throw new RuntimeException("Error after seed: " +
len + " elements, at pos " + pos);
}

public static void throwContentsError(int l, int r, int len, int pos) {
throwError("in contents", l, r, len, pos);
}

public static void throwHeadError(int l, int r, int len, int pos) {
throwError("in head", l, r, len, pos);
}

public static void throwTailError(int l, int r, int len, int pos) {
throwError("in tail", l, r, len, pos);
}

private static void throwError(String phase, int l, int r, int len, int pos) {
throw new RuntimeException("Error " + phase + ": " +
len + " elements, " +
"[" + l + ", " + (l+len) + ") -> " +
"[" + r + ", " + (r+len) + "), " +
"at pos " + pos);
}

protected abstract void testWith(int size, int l, int r, int len);

public void exhaustiveWith(int size) {
for (int l = 0; l < size; l++) {
for (int r = 0; r < size; r++) {
int maxLen = Math.min(size - l, size - r);
for (int len = 0; len <= maxLen; len++) {
testWith(size, l, r, len);
}
}
}
}

public void fuzzWith(Random rand, int size) {
// Some basic checks first
testWith(size, 0, 1, 1);
testWith(size, 0, 1, size-1);

// Test disjoint:
for (int c = 0; c < FUZZ_COUNT; c++) {
int l = rand.nextInt(size / 2);
int len = rand.nextInt((size - l) / 2);
int r = (l + len) + rand.nextInt(size - 2*len - l);

if (l >= size) throw new IllegalStateException("l is out of bounds");
if (l + len > size) throw new IllegalStateException("l+len is out of bounds");
if (r >= size) throw new IllegalStateException("r is out of bounds");
if (r + len > size) throw new IllegalStateException("r+len is out of bounds: " + l + " " + r + " " + len + " " + size);
if (l + len > r) throw new IllegalStateException("Not disjoint");

testWith(size, l, r, len);
testWith(size, r, l, len);
}

// Test conjoint:
for (int c = 0; c < FUZZ_COUNT; c++) {
int l = rand.nextInt(size);
int len = rand.nextInt(size - l);
int r = Math.min(l + (len > 0 ? rand.nextInt(len) : 0), size - len);

if (l >= size) throw new IllegalStateException("l is out of bounds");
if (l + len > size) throw new IllegalStateException("l+len is out of bounds");
if (r >= size) throw new IllegalStateException("r is out of bounds");
if (r + len > size) throw new IllegalStateException("r+len is out of bounds: " + l + " " + r + " " + len + " " + size);
if (l + len < r) throw new IllegalStateException("Not conjoint");

testWith(size, l, r, len);
testWith(size, r, l, len);
shipilev marked this conversation as resolved.
Show resolved Hide resolved
}
}

public void run(Random rand) {
// Exhaustive on all small arrays
for (int size = 1; size <= EXHAUSTIVE_SIZES; size++) {
exhaustiveWith(size);
}

// Fuzz powers of ten
for (int size = 10; size < MAX_SIZE; size *= 10) {
if (size <= EXHAUSTIVE_SIZES) continue;
fuzzWith(rand, size - 1);
fuzzWith(rand, size);
fuzzWith(rand, size + 1);
}

// Fuzz powers of two
for (int size = 2; size < MAX_SIZE; size *= 2) {
if (size <= EXHAUSTIVE_SIZES) continue;
fuzzWith(rand, size - 1);
fuzzWith(rand, size);
fuzzWith(rand, size + 1);
}
}

}
@@ -0,0 +1,164 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/


import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Random;

import jdk.test.lib.Platform;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;

import jdk.test.whitebox.cpuinfo.CPUInfo;

public abstract class StressArrayCopyDriver {

// These tests are remarkably memory bandwidth hungry. Running multiple
// configs in parallel makes sense only when running a single test in
// isolation, and only on machines with many memory channels. In common
// testing, or even running all arraycopy stress tests at once, overloading
// the system with many configs become counter-productive very quickly.
//
// The sweet-spot seems to be 2. Default to it, and allow users to override.
static final int MAX_PARALLELISM = Integer.getInteger("maxParallelism", 2);

private static List<String> mix(List<String> o, String... mix) {
List<String> n = new ArrayList<>(o);
for (String m : mix) {
n.add(m);
}
return n;
}

private static List<List<String>> product(List<List<String>> list, String... mix) {
List<List<String>> newList = new ArrayList<>();
for (List<String> c : list) {
for (String m : mix) {
newList.add(mix(c, m));
}
}
return newList;
}

private static List<List<String>> alternate(List<List<String>> list, String opt) {
return product(list, "-XX:+" + opt, "-XX:-" + opt);
}

private static boolean containsFuzzy(List<String> list, String sub) {
for (String s : list) {
if (s.contains(sub)) return true;
}
return false;
}

public static void main(String... args) throws Exception {
if (args.length < 1) {
throw new IllegalArgumentException("Should provide at least 1 argument");
}

String className = args[0];

List<List<String>> configs = new ArrayList<>();
List<String> cpuFeatures = CPUInfo.getFeatures();

if (Platform.isX64() || Platform.isX86()) {
// If CPU features were not found, provide a default config.
if (cpuFeatures.isEmpty()) {
configs.add(new ArrayList());
}

// Otherwise, select the tests that make sense on current platform.
if (containsFuzzy(cpuFeatures, "avx512")) {
configs.add(List.of("-XX:UseAVX=3"));
}
if (containsFuzzy(cpuFeatures, "avx2")) {
configs.add(List.of("-XX:UseAVX=2"));
}
if (containsFuzzy(cpuFeatures, "avx")) {
configs.add(List.of("-XX:UseAVX=1"));
}
if (containsFuzzy(cpuFeatures, "sse4")) {
configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=4"));
}
if (containsFuzzy(cpuFeatures, "sse3")) {
configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=3"));
}
if (containsFuzzy(cpuFeatures, "sse2")) {
configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=2"));
}

// x86_64 always has UseSSE >= 2. These lower configurations only
// make sense for x86_32.
if (Platform.isX86()) {
if (containsFuzzy(cpuFeatures, "sse")) {
configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=1"));
}

configs.add(List.of("-XX:UseAVX=0", "-XX:UseSSE=0"));
}

// Alternate configs with other flags
if (Platform.isX64()) {
configs = alternate(configs, "UseCompressedOops");
}
configs = alternate(configs, "UseUnalignedLoadStores");

} else if (Platform.isAArch64()) {
// AArch64.
configs.add(new ArrayList());

// Alternate configs with other flags
configs = alternate(configs, "UseCompressedOops");
configs = alternate(configs, "UseSIMDForMemoryOps");
} else {
// Generic config.
configs.add(new ArrayList());
}

Deque<OutputAnalyzer> oas = new ArrayDeque<>();
int jobs = 0;

for (List<String> c : configs) {
ProcessBuilder pb = ProcessTools.createTestJvm(mix(c, "-Xmx256m", className));
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
oas.addLast(oa);
if (++jobs >= MAX_PARALLELISM) {
// Pop and block wait
oa = oas.pollFirst();
oa.shouldHaveExitValue(0);
jobs--;
}
}

// Drain the rest
while (!oas.isEmpty()) {
OutputAnalyzer oa = oas.pollFirst();
oa.shouldHaveExitValue(0);
}
}

}