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&lt;N; line++)
92  *         for (int column=0; column&lt;N; column++) {
93  *             int sum = 0;
94  *             for (int k=0; k&lt;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>&nbsp;&nbsp;
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>&nbsp;&nbsp;
180      * <code>java numeric008 [-verbose] [-performance] <i>matrixSize</i>
181      * <i>iterations</i></code>
182      * <p>
183      * <p>Here:
184      * <br>&nbsp;&nbsp;<code>-verbose</code> -
185      * keyword, which alows to print execution trace
186      * <br>&nbsp;&nbsp;<code>-performance</code> -
187      * keyword, which alows performance testing
188      * <br>&nbsp;&nbsp;<code><i>matrixSize</i></code> -
189      * number of rows (and columns) in square matrix <code>A</code>
190      * <br>&nbsp;&nbsp;<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