0264b050f6
Reviewed-by: epavlova, dholmes
386 lines
14 KiB
Java
386 lines
14 KiB
Java
/*
|
|
* Copyright (c) 1999, 2020, 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
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @key stress randomness
|
|
*
|
|
* @summary converted from VM testbase nsk/stress/numeric/numeric006.
|
|
* VM testbase keywords: [stress, slow, nonconcurrent, quick]
|
|
* VM testbase readme:
|
|
* DESCRIPTION
|
|
* This test calculates the product A*A for a square matrix A of the type
|
|
* float[][]. Elements of the matrix A are initiated with random numbers,
|
|
* so that optimizing compiler could not eliminate any essential portion
|
|
* of calculations.
|
|
* Calculation of the product A*A is iterated three times, and result of
|
|
* the 1st iteration is compared to result of the 3rd iteration. HotSpot
|
|
* releases 1.0 and 1.3 seem to fail to adjust itself for better performance
|
|
* in 1st iteration, while 3rd iteration usually runs much faster. So, the
|
|
* 1st iteration is probably executed by HotSpot interpreter, and HotSpot
|
|
* compiler is probably involved to execute the 3rd iteration. The test
|
|
* just tries to check if HotSpot compiler produces the same results as the
|
|
* HotSpot interpreter.
|
|
* By the way, the test checks JVM performance. The test is treated failed
|
|
* due to poor performance, if 1st iteration is essentially slower than the
|
|
* 3rd iteration. The calculations algorithm is encoded as compact 3-levels
|
|
* cycle like:
|
|
* for (int line=0; line<N; line++)
|
|
* for (int column=0; column<N; column++) {
|
|
* float sum = 0;
|
|
* for (int k=0; k<N; k++)
|
|
* sum += A[line][k] * A[k][column];
|
|
* AA[line][column] = sum;
|
|
* }
|
|
* In this test, N=300, so that A is 300x300 matrix; and multiplication
|
|
* A[line][k]*A[k][column] is executed 300**3=27 millions times in each
|
|
* execution of this cycle. I believe, that this is HotSpot bug to do not
|
|
* adjust itself for best performance during such a huge series of executions
|
|
* of the same portion of program code.
|
|
* COMMENTS
|
|
* See the bug-report:
|
|
* #4242172 (P3/S5) 2.0: poor performance in matrix calculations
|
|
* @library /test/lib
|
|
* @run main/othervm nsk.stress.numeric.numeric006.numeric006 300 3
|
|
*/
|
|
|
|
package nsk.stress.numeric.numeric006;
|
|
|
|
import java.io.PrintStream;
|
|
import java.util.Random;
|
|
import jdk.test.lib.Utils;
|
|
|
|
/**
|
|
* This test calculates the product <code>A<sup>.</sup>A</code> for
|
|
* a square matrix <code>A</code> of the type <code>float[][]</code>.
|
|
* Elements of the matrix <code>A</code> are initiated with random numbers,
|
|
* so that optimizing compiler could not eliminate any essential portion
|
|
* of calculations.
|
|
* <p>
|
|
* <p>Calculation of the product <code>A<sup>.</sup>A</code> is iterated three
|
|
* times, and result of the 1<sup>st</sup> iteration is compared to result of
|
|
* the 3<sup>rd</sup> iteration. HotSpot 1.0 and 1.3 seem to fail to adjust
|
|
* itself for better performance in 1<sup>st</sup> iteration, while 3<sup>rd</sup>
|
|
* iteration usually runs much faster. So, 1<sup>st</sup> iteration is probably
|
|
* executed by HotSpot interpreter, and HotSpot compiler is probably involved to
|
|
* execute the 3<sup>rd</sup> iteration. The test just tries to check if HotSpot
|
|
* compiler produces the same results as the HotSpot interpreter.
|
|
* <p>
|
|
* <p>By the way, the test checks JVM performance. The test is treated failed
|
|
* due to poor performance, if 1<sup>st</sup> iteration is essentially slower
|
|
* than the 3<sup>rd</sup> iteration. The calculations algorithm is encoded
|
|
* as compact ``canonical'' 3-levels cycle like:
|
|
* <pre>
|
|
* for (int line=0; line<N; line++)
|
|
* for (int column=0; column<N; column++) {
|
|
* float sum = 0;
|
|
* for (int k=0; k<N; k++)
|
|
* sum += A[line][k] * A[k][column];
|
|
* AA[line][column] = sum;
|
|
* }
|
|
* </pre>
|
|
* <p>
|
|
* In this test, <code>N</code>=300, so that <code>A</code> is 300x300 matrix;
|
|
* and multiplication <code>A[line][k]*A[k][column]</code> is executed
|
|
* 300<sup>3</sup>=27 millions times in each iteration of execution of this
|
|
* cycle. I believe, that this is HotSpot bug to do not adjust itself for best
|
|
* performance during such a huge series of executions of the same portion of
|
|
* program code.
|
|
* <p>
|
|
* <p>See the bug-report:
|
|
* <br>
|
|
* #4242172 (P3/S5) 2.0: poor performance in matrix calculations
|
|
*/
|
|
public class numeric006 {
|
|
private static final Random RNG = Utils.getRandomInstance();
|
|
/**
|
|
* When testing performance, single thread calculation is allowed to
|
|
* be 10% slower than multi-threads calculation (<code>TOLERANCE</code>
|
|
* is assigned to 10 now).
|
|
*/
|
|
public static final double TOLERANCE = 100; // 10;
|
|
|
|
/**
|
|
* Re-assign this value to <code>true</code> for better
|
|
* diagnostics.
|
|
*
|
|
* @see #print(Object)
|
|
* @see #println(Object)
|
|
*/
|
|
private static boolean verbose = false;
|
|
|
|
/**
|
|
* Stream to print execution trace and/or error messages.
|
|
* This stream usually equals to <code>System.out</code>
|
|
*/
|
|
private static PrintStream out = null;
|
|
|
|
/**
|
|
* Print error-message.
|
|
*
|
|
* @see #out
|
|
*/
|
|
private static void complain(Object x) {
|
|
out.println("# " + x);
|
|
}
|
|
|
|
/**
|
|
* Print to execution trace, if mode is <code>verbose</code>.
|
|
*
|
|
* @see #verbose
|
|
* @see #out
|
|
*/
|
|
private static void print(Object x) {
|
|
if (verbose)
|
|
out.print(x);
|
|
}
|
|
|
|
/**
|
|
* Print line to execution trace, if mode is <code>verbose</code>.
|
|
*
|
|
* @see #verbose
|
|
* @see #out
|
|
*/
|
|
private static void println(Object x) {
|
|
print(x + "\n");
|
|
}
|
|
|
|
/**
|
|
* Re-invoke <code>run(args,out)</code> in order to simulate
|
|
* JCK-like test interface.
|
|
*/
|
|
public static void main(String args[]) {
|
|
int exitCode = run(args, System.out);
|
|
System.exit(exitCode + 95);
|
|
// JCK-like exit status
|
|
}
|
|
|
|
/**
|
|
* Parse command-line parameters stored in <code>args[]</code> and run
|
|
* the test.
|
|
* <p>
|
|
* <p>Command-line parameters are:
|
|
* <br>
|
|
* <code>java numeric006 [-verbose] [-performance] <i>matrixSize</i>
|
|
* <i>iterations</i></code>
|
|
* <p>
|
|
* <p>Here:
|
|
* <br> <code>-verbose</code> -
|
|
* keyword, which alows to print execution trace
|
|
* <br> <code>-performance</code> -
|
|
* keyword, which alows performance testing
|
|
* <br> <code><i>matrixSize</i></code> -
|
|
* number of rows (and columns) in square matrix <code>A</code>
|
|
* <br> <code><i>iterations</i></code> -
|
|
* compute <code>A*A</code> several times
|
|
*
|
|
* @param args strings array containing command-line parameters
|
|
* @param out the test log, usually <code>System.out</code>
|
|
*/
|
|
public static int run(String args[], PrintStream out) {
|
|
numeric006.out = out;
|
|
|
|
boolean testPerformance = false;
|
|
int numberOfCPU = 1;
|
|
|
|
// Parse parameters starting with "-" (like: "-verbose"):
|
|
|
|
int argsShift = 0;
|
|
for (; argsShift < args.length; argsShift++) {
|
|
String argument = args[argsShift];
|
|
|
|
if (!argument.startsWith("-"))
|
|
break;
|
|
|
|
if (argument.equals("-performance")) {
|
|
testPerformance = true;
|
|
continue;
|
|
}
|
|
|
|
if (argument.equals("-verbose")) {
|
|
verbose = true;
|
|
continue;
|
|
}
|
|
|
|
complain("Cannot recognize argument: args[" + argsShift + "]: " + argument);
|
|
return 2; // failure
|
|
}
|
|
|
|
if (args.length != argsShift + 2) {
|
|
complain("Illegal arguments. Execute:");
|
|
complain(
|
|
" java numeric006 [-verbose] [-performance] [-CPU:number] " +
|
|
"matrixSize iterations");
|
|
return 2; // failure
|
|
}
|
|
|
|
int size = Integer.parseInt(args[argsShift]);
|
|
if ((size < 100) || (size > 10000)) {
|
|
complain("Matrix size should be 100 to 1000 lines & columns.");
|
|
return 2; // failure
|
|
}
|
|
|
|
int iterations = Integer.parseInt(args[argsShift + 1]);
|
|
if ((iterations < 1) || (iterations > 100)) {
|
|
complain("Iterations number should be 1 to 100.");
|
|
return 2; // failure
|
|
}
|
|
|
|
print("Preparing A[" + size + "," + size + "]:");
|
|
float[][] A = newMatrix(size);
|
|
float[][] A1 = new float[size][size];
|
|
float[][] Ai = new float[size][size];
|
|
println(" done.");
|
|
|
|
println("Should try " + iterations + " iteration(s):");
|
|
println("==========================" +
|
|
((iterations > 99) ? "==" : (iterations > 9) ? "=" : ""));
|
|
println("");
|
|
|
|
double overallTime = 0;
|
|
double firstTime = 0;
|
|
double lastTime = 0;
|
|
|
|
for (int i = 1; i <= iterations; i++) {
|
|
double seconds;
|
|
|
|
if (i == 1) {
|
|
seconds = elapsedTime(i, A, A1);
|
|
firstTime = seconds;
|
|
} else {
|
|
seconds = elapsedTime(i, A, Ai);
|
|
lastTime = seconds;
|
|
}
|
|
|
|
overallTime += seconds;
|
|
}
|
|
|
|
double averageTime = overallTime / iterations;
|
|
double averagePerformance = size * size * (size + size) / averageTime / 1e6;
|
|
|
|
println("");
|
|
println("=======================" +
|
|
((iterations > 99) ? "==" : (iterations > 9) ? "=" : ""));
|
|
println("Overall iteration(s): " + iterations);
|
|
println("Overall elapsed time: " + overallTime + " seconds.");
|
|
println("Average elapsed time: " + averageTime + " seconds.");
|
|
println("Average performance: " + averagePerformance + " MFLOPS");
|
|
|
|
println("========================");
|
|
print("Checking accuracy:");
|
|
for (int line = 0; line < size; line++)
|
|
for (int column = 0; column < size; column++)
|
|
if (A1[line][column] != Ai[line][column]) {
|
|
println("");
|
|
complain("Test failed:");
|
|
complain("Different results in 1st and last iterations:");
|
|
complain(" line=" + line + ", column=" + column);
|
|
return 2; // FAILED
|
|
}
|
|
println(" done.");
|
|
|
|
if (testPerformance) {
|
|
print("Checking performance: ");
|
|
if (firstTime > lastTime * (1 + TOLERANCE / 100)) {
|
|
println("");
|
|
complain("Test failed:");
|
|
complain("1st iterartion is essentially slower:");
|
|
complain("Calculation time elapsed (seconds):");
|
|
complain(" 1-st iteration: " + firstTime);
|
|
complain(" last iteration: " + lastTime);
|
|
complain(" tolerance: " + TOLERANCE + "%");
|
|
return 2; // FAILED
|
|
}
|
|
println("done.");
|
|
}
|
|
|
|
println("Test passed.");
|
|
return 0; // PASSED
|
|
}
|
|
|
|
private static double elapsedTime(int i, float[][] A, float[][] AA) {
|
|
int size = A.length;
|
|
|
|
if (i > 1)
|
|
println("");
|
|
println("Iteration #" + i + ":");
|
|
|
|
print("Computing A*A:");
|
|
long mark1 = System.currentTimeMillis();
|
|
setSquare(A, AA);
|
|
long mark2 = System.currentTimeMillis();
|
|
println(" done.");
|
|
|
|
double sec = (mark2 - mark1) / 1000.0;
|
|
double perf = size * size * (size + size) / sec;
|
|
println("Elapsed time: " + sec + " seconds");
|
|
println("Performance: " + perf / 1e6 + " MFLOPS");
|
|
|
|
return sec;
|
|
}
|
|
|
|
/**
|
|
* Compute <code>A*A</code> for the given square matrix <code>A</code>.
|
|
*/
|
|
private static void setSquare(float[][] A, float[][] AA) {
|
|
if (A.length != A[0].length)
|
|
throw new IllegalArgumentException(
|
|
"the argument matrix A should be square matrix");
|
|
if (AA.length != AA[0].length)
|
|
throw new IllegalArgumentException(
|
|
"the resulting matrix AA should be square matrix");
|
|
if (A.length != AA.length)
|
|
throw new IllegalArgumentException(
|
|
"the matrices A and AA should have equal size");
|
|
|
|
int size = A.length;
|
|
|
|
for (int line = 0; line < size; line++)
|
|
for (int column = 0; column < size; column++) {
|
|
float sum = 0;
|
|
for (int k = 0; k < size; k++)
|
|
sum += A[line][k] * A[k][line];
|
|
AA[line][column] = sum;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate new square matrix of the given <code>size</code>
|
|
* and with elements initiated with random numbers.
|
|
*/
|
|
private static float[][] newMatrix(int size) {
|
|
if ((size < 1) || (size > 1000))
|
|
throw new IllegalArgumentException(
|
|
"matrix size should be 1 to 1000");
|
|
|
|
float[][] A = new float[size][size];
|
|
|
|
for (int line = 0; line < size; line++)
|
|
for (int column = 0; column < size; column++)
|
|
A[line][column] = (float) ((1 - 2 * RNG.nextDouble()) * size);
|
|
|
|
return A;
|
|
}
|
|
|
|
}
|