1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
|
/*
* 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/numeric003.
* 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
* long[][]. Elements of the matrix A are initiated with random numbers,
* so that optimizing compiler could not eliminate any essential portion
* of calculations.
* That product A*A is calculated twice: in a single thread, and in N
* separate threads, where NxN is the size of square matrix A. When executing
* in N threads, each thread calculate distinct row of the resulting matrix.
* The test checks if the resulting product A*A is the same when calculated
* in single thread and in N threads.
* By the way, the test checks JVM performance. The test is treated failed
* due to poor performance, if single-thread calculation is essentially
* slower than N-threads calculation (surely, the number of CPUs installed
* on the platform executing the test is taken into account for performance
* testing). Note, that HotSpot may fail to adjust itself for better
* performance in single-thread calculation.
* COMMENTS
* The bug was filed referencing to the same numeric algorithm,
* which is used by this test:
* 4242172 (P3/S5) 2.0: poor performance in matrix calculations
*
* @library /test/lib
* @run main/othervm nsk.stress.numeric.numeric003.numeric003 300 300
*/
package nsk.stress.numeric.numeric003;
import java.io.PrintStream;
import java.util.Random;
import jdk.test.lib.Utils;
/**
* This test calculates the product <b>A</b><sup>.</sup><b>A</b> for
* a square matrix <b>A</b> of the type <code>long[][]</code>.
* Elements of the matrix <b>A</b> are initiated with random numbers,
* so that optimizing compiler could not eliminate any essential portion
* of calculations.
* <p>
* <p>That product <b>A</b><sup>.</sup><b>A</b> is calculated twice: in
* a single thread, and in <i>N</i> separate threads, where <i>N</i>x<i>N</i>
* is the size of square matrix <b>A</b>. When executing in <i>N</i> threads,
* each thread calculate distinct row of the resulting matrix. The test checks
* if the resulting product <b>A</b><sup>.</sup><b>A</b> is the same when
* calculated in single thread and in <i>N</i> threads.
* <p>
* <p>By the way, the test checks JVM performance. The test is treated failed
* due to poor performance, if single-thread calculation is essentially
* slower than <i>N</i>-threads calculation (surely, the number of CPUs
* installed on the platform executing the test is taken into account for
* performance testing). Note, that HotSpot may fail to adjust itself for
* better performance in single-thread calculation.
* <p>
* <p>See the bug-report:
* <br>
* 4242172 (P3/S5) 2.0: poor performance in matrix calculations
*/
public class numeric003 {
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.
*/
private static boolean verbose = false;
private static PrintStream out = null;
/**
* Print error-message to the <code>out<code>.
*/
private static void complain(Object x) {
out.println("# " + x);
}
private static void print(Object x) {
if (verbose)
out.print(x);
}
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 numeric003 [-verbose] [-performance] [-CPU:<i>number</i>]
* <i>matrixSize</i> [<i>threads</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>number</i></code> -
* number of CPU installed on the computer just executing the test
* <br> <code><i>matrixSize</i></code> -
* number of rows (and columns) in square matrix to be tested
* <br> <code><i>threads</i></code> -
* for multi-thread calculation
* (default: <code><i>matrixSize</i></code>)
*
* @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) {
numeric003.out = out;
boolean testPerformance = false;
int numberOfCPU = 1;
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;
}
if (argument.startsWith("-CPU:")) {
String value =
argument.substring("-CPU:".length(), argument.length());
numberOfCPU = Integer.parseInt(value);
if (numberOfCPU < 1) {
complain("Illegal number of CPU: " + argument);
return 2; // failure
}
continue;
}
complain("Cannot recognize argument: args[" + argsShift + "]: " + argument);
return 2; // failure
}
if ((args.length < argsShift + 1) || (args.length > argsShift + 2)) {
complain("Illegal argument(s). Execute:");
complain(
" java numeric003 [-verbose] [-performance] [-CPU:number] " +
"matrixSize [threads]");
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 threads = size;
if (args.length >= argsShift + 2)
threads = Integer.parseInt(args[argsShift + 1]);
if ((threads < 1) || (threads > size)) {
complain("Threads number should be 1 to matrix size.");
return 2; // failure
}
if ((size % threads) != 0) {
complain("Threads number should evenly divide matrix size.");
return 2; // failure
}
print("Preparing A[" + size + "," + size + "]:");
SquareMatrix A = new SquareMatrix(size);
SquareMatrix A1 = new SquareMatrix(size);
SquareMatrix Am = new SquareMatrix(size);
println(" done.");
double singleThread = elapsedTime(out, A, A1, size, 1);
double multiThreads = elapsedTime(out, A, Am, size, threads);
print("Checking accuracy:");
for (int line = 0; line < size; line++)
for (int column = 0; column < size; column++)
if (A1.value[line][column] != Am.value[line][column]) {
println("");
complain("Test failed:");
complain("Different results by single- and multi-threads:");
complain(" line=" + line + ", column=" + column);
complain("A1.value[line][column]=" + A1.value[line][column]);
complain("Am.value[line][column]=" + Am.value[line][column]);
return 2; // FAILED
}
println(" done.");
if (testPerformance) {
print("Checking performance: ");
double elapsed1 = singleThread;
double elapsedM = multiThreads * numberOfCPU;
if (elapsed1 > elapsedM * (1 + TOLERANCE / 100)) {
println("");
complain("Test failed:");
complain("Single-thread calculation is essentially slower:");
complain("Calculation time elapsed (seconds):");
complain(" single thread: " + singleThread);
complain(" multi-threads: " + multiThreads);
complain(" number of CPU: " + numberOfCPU);
complain(" tolerance: " + TOLERANCE + "%");
return 2; // FAILED
}
println("done.");
}
println("Test passed.");
return 0; // PASSED
}
private static double elapsedTime(PrintStream out,
SquareMatrix A, SquareMatrix AA, int size, int threads) {
print("Computing A*A with " + threads + " thread(s):");
long mark1 = System.currentTimeMillis();
AA.setSquareOf(A, threads);
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;
}
/**
* This class computes <code>A*A</code> for square matrix <code>A</code>.
*/
private static class SquareMatrix {
volatile long value[][];
/**
* New square matrix with random elements.
*/
public SquareMatrix(int size) {
value = new long[size][size];
for (int line = 0; line < size; line++)
for (int column = 0; column < size; column++)
value[line][column] = Math.round(RNG.nextDouble() * size);
}
/**
* Update <code>value[][]</code> of <code>this</code> matrix.
*
* @param threads Split computation into the given number of threads.
*/
public void setSquareOf(SquareMatrix A, int threads) {
if (this.value.length != A.value.length)
throw new IllegalArgumentException(
"this.value.length != A.value.length");
int size = value.length;
if ((size % threads) != 0)
throw new IllegalArgumentException("size%threads != 0");
int bunch = size / threads;
Thread task[] = new Thread[threads];
for (int t = 0; t < threads; t++) {
int line0 = bunch * t;
MatrixComputer computer =
new MatrixComputer(value, A.value, line0, bunch);
task[t] = new Thread(computer);
}
for (int t = 0; t < threads; t++)
task[t].start();
for (int t = 0; t < threads; t++)
if (task[t].isAlive())
try {
task[t].join();
} catch (InterruptedException exception) {
throw new RuntimeException(exception.toString());
}
}
/**
* Thread to compute a bunch of lines of matrix square.
*/
private static class MatrixComputer implements Runnable {
private long result[][];
private long source[][];
private int line0;
private int bunch;
/**
* Register a task for matrix multiplication.
*/
public MatrixComputer(
long result[][], long source[][], int line0, int bunch) {
this.result = result; // reference to resulting matrix value
this.source = source; // reference to matrix to be squared
this.line0 = line0; // compute lines from line0 to ...
this.bunch = bunch; // number of resulting lines to compute
}
/**
* Do execute the task just registered for <code>this</code> thread.
*/
public void run() {
int line1 = line0 + bunch;
int size = result.length;
for (int line = line0; line < line1; line++)
for (int column = 0; column < size; column++) {
long sum = 0;
for (int i = 0; i < size; i++)
sum += source[line][i] * source[i][column];
result[line][column] = sum;
}
}
}
}
}
|