1 /* 2 * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @key stress 27 * 28 * @summary converted from VM testbase nsk/stress/numeric/numeric008. 29 * VM testbase keywords: [stress, slow, nonconcurrent, quick] 30 * VM testbase readme: 31 * DESCRIPTION 32 * This test calculates the product A*A for a square matrix A of the type 33 * int[][]. Elements of the matrix A are initiated with random numbers, 34 * so that optimizing compiler could not eliminate any essential portion 35 * of calculations. 36 * Calculation of the product A*A is iterated three times, and result of 37 * the 1st iteration is compared to result of the 3rd iteration. HotSpot 38 * releases 1.0 and 1.3 seem to fail to adjust itself for better performance 39 * in 1st iteration, while 3rd iteration usually runs much faster. So, the 40 * 1st iteration is probably executed by HotSpot interpreter, and HotSpot 41 * compiler is probably involved to execute the 3rd iteration. The test 42 * just tries to check if HotSpot compiler produces the same results as the 43 * HotSpot interpreter. 44 * By the way, the test checks JVM performance. The test is treated failed 45 * due to poor performance, if 1st iteration is essentially slower than the 46 * 3rd iteration. The calculations algorithm is encoded as compact 3-levels 47 * cycle like: 48 * for (int line=0; line<N; line++) 49 * for (int column=0; column<N; column++) { 50 * int sum = 0; 51 * for (int k=0; k<N; k++) 52 * sum += A[line][k] * A[k][column]; 53 * AA[line][column] = sum; 54 * } 55 * In this test, N=300, so that A is 300x300 matrix; and multiplication 56 * A[line][k]*A[k][column] is executed 300**3=27 millions times in each 57 * execution of this cycle. I believe, that this is HotSpot bug to do not 58 * adjust itself for best performance during such a huge series of executions 59 * of the same portion of program code. 60 * COMMENTS 61 * See the bug-report: 62 * #4242172 (P3/S5) 2.0: poor performance in matrix calculations 63 * @run main/othervm nsk.stress.numeric.numeric008.numeric008 300 3 64 */ 65 66 package nsk.stress.numeric.numeric008; 67 68 import java.io.PrintStream; 69 70 /** 71 * This test calculates the product <code>A<sup>.</sup>A</code> for 72 * a square matrix <code>A</code> of the type <code>int[][]</code>. 73 * Elements of the matrix <code>A</code> are initiated with random numbers, 74 * so that optimizing compiler could not eliminate any essential portion 75 * of calculations. 76 * <p> 77 * <p>Calculation of the product <code>A<sup>.</sup>A</code> is iterated three 78 * times, and result of the 1<sup>st</sup> iteration is compared to result of 79 * the 3<sup>rd</sup> iteration. HotSpot 1.0 and 1.3 seem to fail to adjust 80 * itself for better performance in 1<sup>st</sup> iteration, while 3<sup>rd</sup> 81 * iteration usually runs much faster. So, 1<sup>st</sup> iteration is probably 82 * executed by HotSpot interpreter, and HotSpot compiler is probably involved to 83 * execute the 3<sup>rd</sup> iteration. The test just tries to check if HotSpot 84 * compiler produces the same results as the HotSpot interpreter. 85 * <p> 86 * <p>By the way, the test checks JVM performance. The test is treated failed 87 * due to poor performance, if 1<sup>st</sup> iteration is essentially slower 88 * than the 3<sup>rd</sup> iteration. The calculations algorithm is encoded 89 * as compact ``canonical'' 3-levels cycle like: 90 * <pre> 91 * for (int line=0; line<N; line++) 92 * for (int column=0; column<N; column++) { 93 * int sum = 0; 94 * for (int k=0; k<N; k++) 95 * sum += A[line][k] * A[k][column]; 96 * AA[line][column] = sum; 97 * } 98 * </pre> 99 * <p> 100 * In this test, <code>N</code>=300, so that <code>A</code> is 300x300 matrix; 101 * and multiplication <code>A[line][k]*A[k][column]</code> is executed 102 * 300<sup>3</sup>=27 millions times in each iteration of execution of this 103 * cycle. I believe, that this is HotSpot bug to do not adjust itself for best 104 * performance during such a huge series of executions of the same portion of 105 * program code. 106 * <p> 107 * <p>See the bug-report: 108 * <br> 109 * #4242172 (P3/S5) 2.0: poor performance in matrix calculations 110 */ 111 public class numeric008 { 112 /** 113 * When testing performance, single thread calculation is allowed to 114 * be 10% slower than multi-threads calculation (<code>TOLERANCE</code> 115 * is assigned to 10 now). 116 */ 117 public static final double TOLERANCE = 100; // 10; 118 119 /** 120 * Re-assign this value to <code>true</code> for better 121 * diagnostics. 122 * 123 * @see #print(Object) 124 * @see #println(Object) 125 */ 126 private static boolean verbose = false; 127 128 /** 129 * Stream to print execution trace and/or error messages. 130 * This stream usually equals to <code>System.out</code> 131 */ 132 private static PrintStream out = null; 133 134 /** 135 * Print error-message. 136 * 137 * @see #out 138 */ complain(Object x)139 private static void complain(Object x) { 140 out.println("# " + x); 141 } 142 143 /** 144 * Print to execution trace, if mode is <code>verbose</code>. 145 * 146 * @see #verbose 147 * @see #out 148 */ print(Object x)149 private static void print(Object x) { 150 if (verbose) 151 out.print(x); 152 } 153 154 /** 155 * Print line to execution trace, if mode is <code>verbose</code>. 156 * 157 * @see #verbose 158 * @see #out 159 */ println(Object x)160 private static void println(Object x) { 161 print(x + "\n"); 162 } 163 164 /** 165 * Re-invoke <code>run(args,out)</code> in order to simulate 166 * JCK-like test interface. 167 */ main(String args[])168 public static void main(String args[]) { 169 int exitCode = run(args, System.out); 170 System.exit(exitCode + 95); 171 // JCK-like exit status 172 } 173 174 /** 175 * Parse command-line parameters stored in <code>args[]</code> and run 176 * the test. 177 * <p> 178 * <p>Command-line parameters are: 179 * <br> 180 * <code>java numeric008 [-verbose] [-performance] <i>matrixSize</i> 181 * <i>iterations</i></code> 182 * <p> 183 * <p>Here: 184 * <br> <code>-verbose</code> - 185 * keyword, which alows to print execution trace 186 * <br> <code>-performance</code> - 187 * keyword, which alows performance testing 188 * <br> <code><i>matrixSize</i></code> - 189 * number of rows (and columns) in square matrix <code>A</code> 190 * <br> <code><i>iterations</i></code> - 191 * compute <code>A*A</code> several times 192 * 193 * @param args strings array containing command-line parameters 194 * @param out the test log, usually <code>System.out</code> 195 */ run(String args[], PrintStream out)196 public static int run(String args[], PrintStream out) { 197 numeric008.out = out; 198 199 boolean testPerformance = false; 200 int numberOfCPU = 1; 201 202 // Parse parameters starting with "-" (like: "-verbose"): 203 204 int argsShift = 0; 205 for (; argsShift < args.length; argsShift++) { 206 String argument = args[argsShift]; 207 208 if (!argument.startsWith("-")) 209 break; 210 211 if (argument.equals("-performance")) { 212 testPerformance = true; 213 continue; 214 } 215 216 if (argument.equals("-verbose")) { 217 verbose = true; 218 continue; 219 } 220 221 complain("Cannot recognize argument: args[" + argsShift + "]: " + argument); 222 return 2; // failure 223 } 224 225 if (args.length != argsShift + 2) { 226 complain("Illegal arguments. Execute:"); 227 complain( 228 " java numeric008 [-verbose] [-performance] [-CPU:number] " + 229 "matrixSize iterations"); 230 return 2; // failure 231 } 232 233 int size = Integer.parseInt(args[argsShift]); 234 if ((size < 100) || (size > 10000)) { 235 complain("Matrix size should be 100 to 1000 lines & columns."); 236 return 2; // failure 237 } 238 239 int iterations = Integer.parseInt(args[argsShift + 1]); 240 if ((iterations < 1) || (iterations > 100)) { 241 complain("Iterations number should be 1 to 100."); 242 return 2; // failure 243 } 244 245 print("Preparing A[" + size + "," + size + "]:"); 246 int[][] A = newMatrix(size); 247 int[][] A1 = new int[size][size]; 248 int[][] Ai = new int[size][size]; 249 println(" done."); 250 251 println("Should try " + iterations + " iteration(s):"); 252 println("==========================" + 253 ((iterations > 99) ? "==" : (iterations > 9) ? "=" : "")); 254 println(""); 255 256 double overallTime = 0; 257 double firstTime = 0; 258 double lastTime = 0; 259 260 for (int i = 1; i <= iterations; i++) { 261 double seconds; 262 263 if (i == 1) { 264 seconds = elapsedTime(i, A, A1); 265 firstTime = seconds; 266 } else { 267 seconds = elapsedTime(i, A, Ai); 268 lastTime = seconds; 269 } 270 271 overallTime += seconds; 272 } 273 274 double averageTime = overallTime / iterations; 275 double averagePerformance = size * size * (size + size) / averageTime / 1e6; 276 277 println(""); 278 println("=======================" + 279 ((iterations > 99) ? "==" : (iterations > 9) ? "=" : "")); 280 println("Overall iteration(s): " + iterations); 281 println("Overall elapsed time: " + overallTime + " seconds."); 282 println("Average elapsed time: " + averageTime + " seconds."); 283 println("Average performance: " + averagePerformance + " MFLOPS"); 284 285 println("========================"); 286 print("Checking accuracy:"); 287 for (int line = 0; line < size; line++) 288 for (int column = 0; column < size; column++) 289 if (A1[line][column] != Ai[line][column]) { 290 println(""); 291 complain("Test failed:"); 292 complain("Different results in 1st and last iterations:"); 293 complain(" line=" + line + ", column=" + column); 294 return 2; // FAILED 295 } 296 println(" done."); 297 298 if (testPerformance) { 299 print("Checking performance: "); 300 if (firstTime > lastTime * (1 + TOLERANCE / 100)) { 301 println(""); 302 complain("Test failed:"); 303 complain("1st iterartion is essentially slower:"); 304 complain("Calculation time elapsed (seconds):"); 305 complain(" 1-st iteration: " + firstTime); 306 complain(" last iteration: " + lastTime); 307 complain(" tolerance: " + TOLERANCE + "%"); 308 return 2; // FAILED 309 } 310 println("done."); 311 } 312 313 println("Test passed."); 314 return 0; // PASSED 315 } 316 elapsedTime(int i, int[][] A, int[][] AA)317 private static double elapsedTime(int i, int[][] A, int[][] AA) { 318 int size = A.length; 319 320 if (i > 1) 321 println(""); 322 println("Iteration #" + i + ":"); 323 324 print("Computing A*A:"); 325 long mark1 = System.currentTimeMillis(); 326 setSquare(A, AA); 327 long mark2 = System.currentTimeMillis(); 328 println(" done."); 329 330 double sec = (mark2 - mark1) / 1000.0; 331 double perf = size * size * (size + size) / sec; 332 println("Elapsed time: " + sec + " seconds"); 333 println("Performance: " + perf / 1e6 + " MFLOPS"); 334 335 return sec; 336 } 337 338 /** 339 * Compute <code>A*A</code> for the given square matrix <code>A</code>. 340 */ setSquare(int[][] A, int[][] AA)341 private static void setSquare(int[][] A, int[][] AA) { 342 if (A.length != A[0].length) 343 throw new IllegalArgumentException( 344 "the argument matrix A should be square matrix"); 345 if (AA.length != AA[0].length) 346 throw new IllegalArgumentException( 347 "the resulting matrix AA should be square matrix"); 348 if (A.length != AA.length) 349 throw new IllegalArgumentException( 350 "the matrices A and AA should have equal size"); 351 352 int size = A.length; 353 354 for (int line = 0; line < size; line++) 355 for (int column = 0; column < size; column++) { 356 int sum = 0; 357 for (int k = 0; k < size; k++) 358 sum += A[line][k] * A[k][line]; 359 AA[line][column] = sum; 360 } 361 } 362 363 /** 364 * Generate new square matrix of the given <code>size</code> 365 * and with elements initiated with random numbers. 366 */ newMatrix(int size)367 private static int[][] newMatrix(int size) { 368 if ((size < 1) || (size > 1000)) 369 throw new IllegalArgumentException( 370 "matrix size should be 1 to 1000"); 371 372 int[][] A = new int[size][size]; 373 374 for (int line = 0; line < size; line++) 375 for (int column = 0; column < size; column++) 376 A[line][column] = Math.round((float) ((1 - 2 * Math.random()) * size)); 377 378 return A; 379 } 380 381 } 382