Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/stress/numeric/numeric010.java
41159 views
/*1* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @key stress randomness26*27* @summary converted from VM testbase nsk/stress/numeric/numeric010.28* VM testbase keywords: [stress, slow, nonconcurrent, quick]29* VM testbase readme:30* DESCRIPTION31* This test calculates the product A*A for a square matrix A, and checks32* if such product is calculated correctly. Elements of the matrix A are33* initiated with integer numbers, so that A*A must be the same if calculated34* with double, float, long, or int precision. The test just checks, if35* double, float, long, and int variants of the product calculation result36* in the same A*A matrix.37* The product A*A is calculated twice: in a single thread, and in N separate38* threads, where NxN is the size of square matrix A. When executing in N39* threads, each thread calculate distinct row of the resulting matrix.40* HotSpot releases 1.0 and 1.3 seem to do not adjust JVM for better41* performance in single-thread calculation, while milti-threads calculation42* usually runs much faster. I guess, that the 1-thread calculation is probably43* executed by HotSpot interpreter, and HotSpot compiler is probably involved44* to execute N-threads calculation. So, the test apparently checks accuracy45* of A*A calculation in both compilation and interpretation modes.46* By the way, the test checks JVM performance. The test is treated failed47* due to poor performance, if single-thread calculation is essentially48* slower than N-threads calculation (surely, the number of CPUs installed49* on the platform executing the test is taken into account for performance50* testing). The calculation algorithm is encoded with 3-levels cycle like:51* for (int line=0; line<N; line++)52* for (int column=0; column<N; column++) {53* float sum = 0;54* for (int k=0; k<N; k++)55* sum += A[line][k] A[k][column];56* AA[line][column] = sum;57* }58* In this test, N=200, so that A is 200x200 matrix; and multiplication59* A[line][k]*A[k][column] is executed 200**3=8 millions times in this60* cycle. I believe, that this is HotSpot bug to do not adjust JVM for61* best performance during such a huge series of executions of the rather62* compact portion of program code.63* COMMENTS64* The bug was filed referencing to the same numeric algorithm,65* which is used by this test:66* 4242172 (P3/S5) 2.0: poor performance in matrix calculations67* Note, that despite HotSpot works faster in milti-thread calculations,68* it still remains essentially slower than classic VM with JIT on.69*70* @library /test/lib71* @run main/othervm nsk.stress.numeric.numeric010.numeric010 200 20072*/7374package nsk.stress.numeric.numeric010;7576import java.io.PrintStream;77import java.util.Random;78import jdk.test.lib.Utils;7980/**81* This test calculates the product <code>A<sup>.</sup>A</code> for a square82* matrix <code>A</code>, and checks if such product is calculated correctly.83* Elements of the matrix <code>A</code> are initiated with integer numbers,84* so that <code>A<sup>.</sup>A</code> must be the same if calculated with85* <code>double</code>, <code>float</code>, <code>long</code>, or86* <code>int</code> precision. The test just checks, if <code>double</code>,87* <code>float</code>, <code>long</code>, and <code>int</code> variants of88* the product calculation result in the same <code>A<sup>.</sup>A</code>89* matrix.90* <p>91* <p>The product <code>A<sup>.</sup>A</code> is calculated twice: in a single92* thread, and in <code>N</code> separate threads, where <code>NxN</code> is93* the size of square matrix <code>A</code>. When executing in <code>N</code>94* threads, each thread calculate distinct row of the resulting matrix. HotSpot95* releases 1.0 and 1.3 seem to do not adjust JVM for better performance in96* single-thread calculation, while milti-threads calculation usually runs much97* faster. I guess, that the 1-thread calculation is probably executed by HotSpot98* interpreter, and HotSpot compiler is probably involved to execute99* <code>N</code>-threads calculation. So, the test apparently checks accuracy100* of <code>A<sup>.</sup>A</code> calculation in both compilation and101* interpretation modes.102* <p>103* <p>By the way, the test checks JVM performance. The test is treated failed104* due to poor performance, if single-thread calculation is essentially105* slower than <code>N</code>-threads calculation (surely, the number of CPUs106* installed on the platform executing the test is taken into account for107* performance testing). The calculation algorithm is encoded with 3-levels108* cycle like:109* <pre>110* for (int line=0; line<N; line++)111* for (int column=0; column<N; column++) {112* float sum = 0;113* for (int k=0; k<N; k++)114* sum += A[line][k] * A[k][column];115* AA[line][column] = sum;116* }117* </pre>118* <p>119* In this test, <code>N</code>=200, so that <code>A</code> is 200x200 matrix;120* and multiplication <code>A[line][k]*A[k][column]</code> is executed121* 200<sup>3</sup>=8 millions times in this cycle. I believe, that this is HotSpot122* bug to do not adjust JVM for best performance during such a huge series of123* executions of the rather compact portion of program code.124* <p>125* <p>See the bug-report:126* <br> 127* 4242172 (P3/S5) 2.0: poor performance in matrix calculations128*/129public class numeric010 {130private static final Random RNG = Utils.getRandomInstance();131/**132* When testing performance, 1-thread calculation is allowed to be 10%133* slower than multi-thread calculation (<code>tolerance</code> is134* assigned to 10 now).135*/136public static double tolerance = 100; // 10;137138/**139* Re-assign this value to <code>true</code> for better diagnostics.140*141* @see #print(Object)142* @see #println(Object)143*/144private static boolean verbose = false;145146/**147* Stream to print execution trace and/or error messages.148* This stream usually equals to <code>System.out</code>149*/150private static PrintStream out = null;151152/**153* Print error-message.154*155* @see #out156*/157private static void complain(Object x) {158out.println("# " + x);159}160161/**162* Print to execution trace, if mode is <code>verbose</code>.163*164* @see #verbose165* @see #out166*/167private static void print(Object x) {168if (verbose)169out.print(x);170}171172/**173* Print line to execution trace, if mode is <code>verbose</code>.174*175* @see #verbose176* @see #out177*/178private static void println(Object x) {179print(x + "\n");180}181182/**183* Re-invoke <code>run(args,out)</code> in order to simulate184* JCK-like test interface.185*/186public static void main(String args[]) {187int exitCode = run(args, System.out);188System.exit(exitCode + 95);189// JCK-like exit status190}191192/**193* Parse command-line parameters stored in <code>args[]</code> and run194* the test.195* <p>196* <p>Command-line parameters are:197* <br> 198* <code>java numeric010 [-verbose] [-performance]199* [-tolerance:<i>percents</i>] [-CPU:<i>number</i>]200* <i>matrixSize</i> [<i>threads</i>]</code>201* <p>202* <p>Here:203* <br> <code>-verbose</code> -204* keyword, which alows to print execution trace205* <br> <code>-performance</code> -206* keyword, which alows performance testing207* <br> <code>-tolerance</code> -208* setup tolerance of performance checking209* <br> <code><i>percents</i></code> -210* 1-thread calculation is allowed to be211* <code><i>percents</i></code>% slower212* <br> <code><i>number</i></code> -213* number of CPU installed on the computer just executing the test214* <br> <code><i>matrixSize</i></code> -215* number of rows (and columns) in square matrix to be tested216* <br> <code><i>threads</i></code> -217* for multi-thread calculation218* (default: <code><i>matrixSize</i></code>)219*220* @param args strings array containing command-line parameters221* @param out the test log, usually <code>System.out</code>222*/223public static int run(String args[], PrintStream out) {224numeric010.out = out;225226boolean testPerformance = false;227int numberOfCPU = 1;228229int argsShift = 0;230for (; argsShift < args.length; argsShift++) {231String argument = args[argsShift];232233if (!argument.startsWith("-"))234break;235236if (argument.equals("-performance")) {237testPerformance = true;238continue;239}240241if (argument.equals("-verbose")) {242verbose = true;243continue;244}245246if (argument.startsWith("-tolerance:")) {247String percents =248argument.substring("-tolerance:".length(), argument.length());249tolerance = Integer.parseInt(percents);250251if ((tolerance < 0) || (tolerance > 100)) {252complain("Tolerance should be 0 to 100%: " + argument);253return 2; // failure254}255continue;256}257258if (argument.startsWith("-CPU:")) {259String value =260argument.substring("-CPU:".length(), argument.length());261numberOfCPU = Integer.parseInt(value);262263if (numberOfCPU < 1) {264complain("Illegal number of CPU: " + argument);265return 2; // failure266}267continue;268}269270complain("Cannot recognize argument: args[" + argsShift + "]: " + argument);271return 2; // failure272}273274if ((args.length < argsShift + 1) || (args.length > argsShift + 2)) {275complain("Illegal argument(s). Execute:");276complain(277" java numeric010 [-verbose] [-performance] " +278"[-tolerance:percents] [-CPU:number] matrixSize [threads]");279return 2; // failure280}281282int size = Integer.parseInt(args[argsShift]);283if ((size < 100) || (size > 10000)) {284complain("Matrix size should be 100 to 1000 lines & columns.");285return 2; // failure286}287288int threads = size;289if (args.length >= argsShift + 2)290threads = Integer.parseInt(args[argsShift + 1]);291if ((threads < 1) || (threads > size)) {292complain("Threads number should be 1 to matrix size.");293return 2; // failure294}295if ((size % threads) != 0) {296complain("Threads number should evenly divide matrix size.");297return 2; // failure298}299300print("Preparing A[" + size + "," + size + "]:");301IntegerMatrix intA = new IntegerMatrix(size);302IntegerMatrix intAA = new IntegerMatrix(size);303LongMatrix longA = new LongMatrix(intA);304LongMatrix longAA = new LongMatrix(intA);305FloatMatrix floatA = new FloatMatrix(intA);306FloatMatrix floatAA = new FloatMatrix(intA);307DoubleMatrix doubleA = new DoubleMatrix(intA);308DoubleMatrix doubleAA = new DoubleMatrix(intA);309println(" done.");310311double elapsed[] = {0, 0};312313for (int i = 0; i < 2; i++) {314double seconds =315elapsedTime((i == 0 ? 1 : threads),316intA, intAA,317longA, longAA,318floatA, floatAA,319doubleA, doubleAA);320elapsed[i] = seconds;321322print("Checking accuracy:");323for (int line = 0; line < size; line++)324for (int column = 0; column < size; column++) {325if (intAA.value[line][column] != longAA.value[line][column]) {326println("");327complain("Test failed:");328complain("Integer and Long results differ at:");329complain(" line=" + line + ", column=" + column);330complain(" intAA.value[line][column]=" + intAA.value[line][column]);331complain("longAA.value[line][column]=" + longAA.value[line][column]);332return 2; // FAILED333}334if (intAA.value[line][column] != floatAA.value[line][column]) {335println("");336complain("Test failed:");337complain("Integer and Float results differ at:");338complain(" line=" + line + ", column=" + column);339complain(" intAA.value[line][column]=" + intAA.value[line][column]);340complain("floatAA.value[line][column]=" + floatAA.value[line][column]);341return 2; // FAILED342}343if (intAA.value[line][column] != doubleAA.value[line][column]) {344println("");345complain("Test failed:");346complain("Integer and Double results differ at:");347complain(" line=" + line + ", column=" + column);348complain(" intAA.value[line][column]=" + intAA.value[line][column]);349complain("doubleAA.value[line][column]=" + doubleAA.value[line][column]);350return 2; // FAILED351}352}353println(" done.");354}355356double overallTime = elapsed[0] + elapsed[1];357double averageTime = overallTime / 2; // 2 excutions358double averagePerformance = 4 * size * size * (size + size) / averageTime / 1e6;359println("");360println("Overall elapsed time: " + overallTime + " seconds.");361println("Average elapsed time: " + averageTime + " seconds.");362println("Average performance: " + averagePerformance + " MOPS");363364if (testPerformance) {365println("");366print("Checking performance: ");367double elapsed1 = elapsed[0];368double elapsedM = elapsed[1] * numberOfCPU;369if (elapsed1 > elapsedM * (1 + tolerance / 100)) {370println("");371complain("Test failed:");372complain("Single-thread calculation is essentially slower:");373complain("Calculation time elapsed (seconds):");374complain(" single thread: " + elapsed[0]);375complain(" multi-threads: " + elapsed[1]);376complain(" number of CPU: " + numberOfCPU);377complain(" tolerance: " + tolerance + "%");378return 2; // FAILED379}380println("done.");381}382383println("Test passed.");384return 0; // PASSED385}386387/**388* Return time (in seconds) elapsed for calculation of matrix389* product <code>A*A</code> with <code>int</code>, <code>long</code>,390* <code>float</code>, and <code>double</code> representations.391*/392private static double elapsedTime(int threads,393IntegerMatrix intA, IntegerMatrix intAA,394LongMatrix longA, LongMatrix longAA,395FloatMatrix floatA, FloatMatrix floatAA,396DoubleMatrix doubleA, DoubleMatrix doubleAA) {397398println("");399print("Computing A*A with " + threads + " thread(s):");400long mark1 = System.currentTimeMillis();401intAA.setSquareOf(intA, threads);402longAA.setSquareOf(longA, threads);403floatAA.setSquareOf(floatA, threads);404doubleAA.setSquareOf(doubleA, threads);405long mark2 = System.currentTimeMillis();406println(" done.");407408int size = intA.size();409double sec = (mark2 - mark1) / 1000.0;410double perf = 4 * size * size * (size + size) / sec;411println("Elapsed time: " + sec + " seconds");412println("Performance: " + perf / 1e6 + " MOPS");413414return sec;415}416417/**418* Compute <code>A*A</code> for <code>int</code> matrix <code>A</code>.419*/420private static class IntegerMatrix {421volatile int value[][];422423/**424* Number of lines and columns in <code>this</code> square matrix.425*/426public int size() {427return value.length;428}429430/**431* New square matrix with random elements.432*/433public IntegerMatrix(int size) {434value = new int[size][size];435for (int line = 0; line < size; line++)436for (int column = 0; column < size; column++)437value[line][column] =438Math.round((float) ((1 - 2 * RNG.nextDouble()) * size));439}440441/**442* Assign <code>this</code> matrix with <code>A*A</code>.443*444* @param threads Split computation into the given number of threads.445*/446public void setSquareOf(IntegerMatrix A, int threads) {447if (this.size() != A.size())448throw new IllegalArgumentException(449"this.size() != A.size()");450451if ((size() % threads) != 0)452throw new IllegalArgumentException("size()%threads != 0");453int bunch = size() / threads;454455Thread task[] = new Thread[threads];456for (int t = 0; t < threads; t++) {457int line0 = bunch * t;458MatrixComputer computer =459new MatrixComputer(value, A.value, line0, bunch);460task[t] = new Thread(computer);461}462463for (int t = 0; t < threads; t++)464task[t].start();465466for (int t = 0; t < threads; t++)467if (task[t].isAlive())468try {469task[t].join();470} catch (InterruptedException exception) {471throw new RuntimeException(exception.toString());472}473}474475/**476* Thread to compute a bunch of lines of matrix square.477*/478private static class MatrixComputer implements Runnable {479private int result[][];480private int source[][];481private int line0;482private int bunch;483484/**485* Register a task for matrix multiplication.486*/487public MatrixComputer(488int result[][], int source[][], int line0, int bunch) {489490this.result = result; // reference to resulting matrix value491this.source = source; // reference to matrix to be squared492this.line0 = line0; // compute lines from line0 to ...493this.bunch = bunch; // number of resulting lines to compute494}495496/**497* Do execute the task just registered for <code>this</code> thread.498*/499public void run() {500int line1 = line0 + bunch;501int size = result.length;502for (int line = line0; line < line1; line++)503for (int column = 0; column < size; column++) {504int sum = 0;505for (int i = 0; i < size; i++)506sum += source[line][i] * source[i][column];507result[line][column] = sum;508}509}510511}512513}514515/**516* Compute <code>A*A</code> for <code>long</code> matrix <code>A</code>.517*/518private static class LongMatrix {519volatile long value[][];520521/**522* Number of lines and columns in <code>this</code> square matrix.523*/524public int size() {525return value.length;526}527528529/**530* New square matrix with the given integer elements.531*/532public LongMatrix(IntegerMatrix A) {533int size = A.size();534value = new long[size][size];535for (int line = 0; line < size; line++)536for (int column = 0; column < size; column++)537value[line][column] = A.value[line][column];538}539540/**541* Assign <code>this</code> matrix with <code>A*A</code>.542*543* @param threads Split computation into the given number of threads.544*/545public void setSquareOf(LongMatrix A, int threads) {546if (this.size() != A.size())547throw new IllegalArgumentException(548"this.size() != A.size()");549550if ((size() % threads) != 0)551throw new IllegalArgumentException("size()%threads != 0");552int bunch = size() / threads;553554Thread task[] = new Thread[threads];555for (int t = 0; t < threads; t++) {556int line0 = bunch * t;557MatrixComputer computer =558new MatrixComputer(value, A.value, line0, bunch);559task[t] = new Thread(computer);560}561562for (int t = 0; t < threads; t++)563task[t].start();564565for (int t = 0; t < threads; t++)566if (task[t].isAlive())567try {568task[t].join();569} catch (InterruptedException exception) {570throw new RuntimeException(exception.toString());571}572}573574/**575* Thread to compute a bunch of lines of matrix square.576*/577private static class MatrixComputer implements Runnable {578private long result[][];579private long source[][];580private int line0;581private int bunch;582583/**584* Register a task for matrix multiplication.585*/586public MatrixComputer(587long result[][], long source[][], int line0, int bunch) {588589this.result = result; // reference to resulting matrix value590this.source = source; // reference to matrix to be squared591this.line0 = line0; // compute lines from line0 to ...592this.bunch = bunch; // number of resulting lines to compute593}594595/**596* Do execute the task just registered for <code>this</code> thread.597*/598public void run() {599int line1 = line0 + bunch;600int size = result.length;601for (int line = line0; line < line1; line++)602for (int column = 0; column < size; column++) {603long sum = 0;604for (int i = 0; i < size; i++)605sum += source[line][i] * source[i][column];606result[line][column] = sum;607}608}609610}611612}613614/**615* Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>.616*/617private static class FloatMatrix {618volatile float value[][];619620/**621* Number of lines and columns in <code>this</code> square matrix.622*/623public int size() {624return value.length;625}626627628/**629* New square matrix with the given integer elements.630*/631public FloatMatrix(IntegerMatrix A) {632int size = A.size();633value = new float[size][size];634for (int line = 0; line < size; line++)635for (int column = 0; column < size; column++)636value[line][column] = A.value[line][column];637}638639/**640* Assign <code>this</code> matrix with <code>A*A</code>.641*642* @param threads Split computation into the given number of threads.643*/644public void setSquareOf(FloatMatrix A, int threads) {645if (this.size() != A.size())646throw new IllegalArgumentException(647"this.size() != A.size()");648649if ((size() % threads) != 0)650throw new IllegalArgumentException("size()%threads != 0");651int bunch = size() / threads;652653Thread task[] = new Thread[threads];654for (int t = 0; t < threads; t++) {655int line0 = bunch * t;656MatrixComputer computer =657new MatrixComputer(value, A.value, line0, bunch);658task[t] = new Thread(computer);659}660661for (int t = 0; t < threads; t++)662task[t].start();663664for (int t = 0; t < threads; t++)665if (task[t].isAlive())666try {667task[t].join();668} catch (InterruptedException exception) {669throw new RuntimeException(exception.toString());670}671}672673/**674* Thread to compute a bunch of lines of matrix square.675*/676private static class MatrixComputer implements Runnable {677private float result[][];678private float source[][];679private int line0;680private int bunch;681682/**683* Register a task for matrix multiplication.684*/685public MatrixComputer(686float result[][], float source[][], int line0, int bunch) {687688this.result = result; // reference to resulting matrix value689this.source = source; // reference to matrix to be squared690this.line0 = line0; // compute lines from line0 to ...691this.bunch = bunch; // number of resulting lines to compute692}693694/**695* Do execute the task just registered for <code>this</code> thread.696*/697public void run() {698int line1 = line0 + bunch;699int size = result.length;700for (int line = line0; line < line1; line++)701for (int column = 0; column < size; column++) {702float sum = 0;703for (int i = 0; i < size; i++)704sum += source[line][i] * source[i][column];705result[line][column] = sum;706}707}708709}710711}712713/**714* Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>.715*/716private static class DoubleMatrix {717volatile double value[][];718719/**720* Number of lines and columns in <code>this</code> square matrix.721*/722public int size() {723return value.length;724}725726727/**728* New square matrix with the given integer elements.729*/730public DoubleMatrix(IntegerMatrix A) {731int size = A.size();732value = new double[size][size];733for (int line = 0; line < size; line++)734for (int column = 0; column < size; column++)735value[line][column] = A.value[line][column];736}737738/**739* Assign <code>this</code> matrix with <code>A*A</code>.740*741* @param threads Split computation into the given number of threads.742*/743public void setSquareOf(DoubleMatrix A, int threads) {744if (this.size() != A.size())745throw new IllegalArgumentException(746"this.size() != A.size()");747748if ((size() % threads) != 0)749throw new IllegalArgumentException("size()%threads != 0");750int bunch = size() / threads;751752Thread task[] = new Thread[threads];753for (int t = 0; t < threads; t++) {754int line0 = bunch * t;755MatrixComputer computer =756new MatrixComputer(value, A.value, line0, bunch);757task[t] = new Thread(computer);758}759760for (int t = 0; t < threads; t++)761task[t].start();762763for (int t = 0; t < threads; t++)764if (task[t].isAlive())765try {766task[t].join();767} catch (InterruptedException exception) {768throw new RuntimeException(exception.toString());769}770}771772/**773* Thread to compute a bunch of lines of matrix square.774*/775private static class MatrixComputer implements Runnable {776private double result[][];777private double source[][];778private int line0;779private int bunch;780781/**782* Register a task for matrix multiplication.783*/784public MatrixComputer(785double result[][], double source[][], int line0, int bunch) {786787this.result = result; // reference to resulting matrix value788this.source = source; // reference to matrix to be squared789this.line0 = line0; // compute lines from line0 to ...790this.bunch = bunch; // number of resulting lines to compute791}792793/**794* Do execute the task just registered for <code>this</code> thread.795*/796public void run() {797int line1 = line0 + bunch;798int size = result.length;799for (int line = line0; line < line1; line++)800for (int column = 0; column < size; column++) {801double sum = 0;802for (int i = 0; i < size; i++)803sum += source[line][i] * source[i][column];804result[line][column] = sum;805}806}807808}809810}811812}813814815