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/numeric010. 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, and checks 33 * if such product is calculated correctly. Elements of the matrix A are 34 * initiated with integer numbers, so that A*A must be the same if calculated 35 * with double, float, long, or int precision. The test just checks, if 36 * double, float, long, and int variants of the product calculation result 37 * in the same A*A matrix. 38 * The product A*A is calculated twice: in a single thread, and in N separate 39 * threads, where NxN is the size of square matrix A. When executing in N 40 * threads, each thread calculate distinct row of the resulting matrix. 41 * HotSpot releases 1.0 and 1.3 seem to do not adjust JVM for better 42 * performance in single-thread calculation, while milti-threads calculation 43 * usually runs much faster. I guess, that the 1-thread calculation is probably 44 * executed by HotSpot interpreter, and HotSpot compiler is probably involved 45 * to execute N-threads calculation. So, the test apparently checks accuracy 46 * of A*A calculation in both compilation and interpretation modes. 47 * By the way, the test checks JVM performance. The test is treated failed 48 * due to poor performance, if single-thread calculation is essentially 49 * slower than N-threads calculation (surely, the number of CPUs installed 50 * on the platform executing the test is taken into account for performance 51 * testing). The calculation algorithm is encoded with 3-levels cycle like: 52 * for (int line=0; line<N; line++) 53 * for (int column=0; column<N; column++) { 54 * float sum = 0; 55 * for (int k=0; k<N; k++) 56 * sum += A[line][k] A[k][column]; 57 * AA[line][column] = sum; 58 * } 59 * In this test, N=200, so that A is 200x200 matrix; and multiplication 60 * A[line][k]*A[k][column] is executed 200**3=8 millions times in this 61 * cycle. I believe, that this is HotSpot bug to do not adjust JVM for 62 * best performance during such a huge series of executions of the rather 63 * compact portion of program code. 64 * COMMENTS 65 * The bug was filed referencing to the same numeric algorithm, 66 * which is used by this test: 67 * 4242172 (P3/S5) 2.0: poor performance in matrix calculations 68 * Note, that despite HotSpot works faster in milti-thread calculations, 69 * it still remains essentially slower than classic VM with JIT on. 70 * 71 * @run main/othervm nsk.stress.numeric.numeric010.numeric010 200 200 72 */ 73 74 package nsk.stress.numeric.numeric010; 75 76 import java.io.PrintStream; 77 78 /** 79 * This test calculates the product <code>A<sup>.</sup>A</code> for a square 80 * matrix <code>A</code>, and checks if such product is calculated correctly. 81 * Elements of the matrix <code>A</code> are initiated with integer numbers, 82 * so that <code>A<sup>.</sup>A</code> must be the same if calculated with 83 * <code>double</code>, <code>float</code>, <code>long</code>, or 84 * <code>int</code> precision. The test just checks, if <code>double</code>, 85 * <code>float</code>, <code>long</code>, and <code>int</code> variants of 86 * the product calculation result in the same <code>A<sup>.</sup>A</code> 87 * matrix. 88 * <p> 89 * <p>The product <code>A<sup>.</sup>A</code> is calculated twice: in a single 90 * thread, and in <code>N</code> separate threads, where <code>NxN</code> is 91 * the size of square matrix <code>A</code>. When executing in <code>N</code> 92 * threads, each thread calculate distinct row of the resulting matrix. HotSpot 93 * releases 1.0 and 1.3 seem to do not adjust JVM for better performance in 94 * single-thread calculation, while milti-threads calculation usually runs much 95 * faster. I guess, that the 1-thread calculation is probably executed by HotSpot 96 * interpreter, and HotSpot compiler is probably involved to execute 97 * <code>N</code>-threads calculation. So, the test apparently checks accuracy 98 * of <code>A<sup>.</sup>A</code> calculation in both compilation and 99 * interpretation modes. 100 * <p> 101 * <p>By the way, the test checks JVM performance. The test is treated failed 102 * due to poor performance, if single-thread calculation is essentially 103 * slower than <code>N</code>-threads calculation (surely, the number of CPUs 104 * installed on the platform executing the test is taken into account for 105 * performance testing). The calculation algorithm is encoded with 3-levels 106 * cycle like: 107 * <pre> 108 * for (int line=0; line<N; line++) 109 * for (int column=0; column<N; column++) { 110 * float sum = 0; 111 * for (int k=0; k<N; k++) 112 * sum += A[line][k] * A[k][column]; 113 * AA[line][column] = sum; 114 * } 115 * </pre> 116 * <p> 117 * In this test, <code>N</code>=200, so that <code>A</code> is 200x200 matrix; 118 * and multiplication <code>A[line][k]*A[k][column]</code> is executed 119 * 200<sup>3</sup>=8 millions times in this cycle. I believe, that this is HotSpot 120 * bug to do not adjust JVM for best performance during such a huge series of 121 * executions of the rather compact portion of program code. 122 * <p> 123 * <p>See the bug-report: 124 * <br> 125 * 4242172 (P3/S5) 2.0: poor performance in matrix calculations 126 */ 127 public class numeric010 { 128 /** 129 * When testing performance, 1-thread calculation is allowed to be 10% 130 * slower than multi-thread calculation (<code>tolerance</code> is 131 * assigned to 10 now). 132 */ 133 public static double tolerance = 100; // 10; 134 135 /** 136 * Re-assign this value to <code>true</code> for better diagnostics. 137 * 138 * @see #print(Object) 139 * @see #println(Object) 140 */ 141 private static boolean verbose = false; 142 143 /** 144 * Stream to print execution trace and/or error messages. 145 * This stream usually equals to <code>System.out</code> 146 */ 147 private static PrintStream out = null; 148 149 /** 150 * Print error-message. 151 * 152 * @see #out 153 */ complain(Object x)154 private static void complain(Object x) { 155 out.println("# " + x); 156 } 157 158 /** 159 * Print to execution trace, if mode is <code>verbose</code>. 160 * 161 * @see #verbose 162 * @see #out 163 */ print(Object x)164 private static void print(Object x) { 165 if (verbose) 166 out.print(x); 167 } 168 169 /** 170 * Print line to execution trace, if mode is <code>verbose</code>. 171 * 172 * @see #verbose 173 * @see #out 174 */ println(Object x)175 private static void println(Object x) { 176 print(x + "\n"); 177 } 178 179 /** 180 * Re-invoke <code>run(args,out)</code> in order to simulate 181 * JCK-like test interface. 182 */ main(String args[])183 public static void main(String args[]) { 184 int exitCode = run(args, System.out); 185 System.exit(exitCode + 95); 186 // JCK-like exit status 187 } 188 189 /** 190 * Parse command-line parameters stored in <code>args[]</code> and run 191 * the test. 192 * <p> 193 * <p>Command-line parameters are: 194 * <br> 195 * <code>java numeric010 [-verbose] [-performance] 196 * [-tolerance:<i>percents</i>] [-CPU:<i>number</i>] 197 * <i>matrixSize</i> [<i>threads</i>]</code> 198 * <p> 199 * <p>Here: 200 * <br> <code>-verbose</code> - 201 * keyword, which alows to print execution trace 202 * <br> <code>-performance</code> - 203 * keyword, which alows performance testing 204 * <br> <code>-tolerance</code> - 205 * setup tolerance of performance checking 206 * <br> <code><i>percents</i></code> - 207 * 1-thread calculation is allowed to be 208 * <code><i>percents</i></code>% slower 209 * <br> <code><i>number</i></code> - 210 * number of CPU installed on the computer just executing the test 211 * <br> <code><i>matrixSize</i></code> - 212 * number of rows (and columns) in square matrix to be tested 213 * <br> <code><i>threads</i></code> - 214 * for multi-thread calculation 215 * (default: <code><i>matrixSize</i></code>) 216 * 217 * @param args strings array containing command-line parameters 218 * @param out the test log, usually <code>System.out</code> 219 */ run(String args[], PrintStream out)220 public static int run(String args[], PrintStream out) { 221 numeric010.out = out; 222 223 boolean testPerformance = false; 224 int numberOfCPU = 1; 225 226 int argsShift = 0; 227 for (; argsShift < args.length; argsShift++) { 228 String argument = args[argsShift]; 229 230 if (!argument.startsWith("-")) 231 break; 232 233 if (argument.equals("-performance")) { 234 testPerformance = true; 235 continue; 236 } 237 238 if (argument.equals("-verbose")) { 239 verbose = true; 240 continue; 241 } 242 243 if (argument.startsWith("-tolerance:")) { 244 String percents = 245 argument.substring("-tolerance:".length(), argument.length()); 246 tolerance = Integer.parseInt(percents); 247 248 if ((tolerance < 0) || (tolerance > 100)) { 249 complain("Tolerance should be 0 to 100%: " + argument); 250 return 2; // failure 251 } 252 continue; 253 } 254 255 if (argument.startsWith("-CPU:")) { 256 String value = 257 argument.substring("-CPU:".length(), argument.length()); 258 numberOfCPU = Integer.parseInt(value); 259 260 if (numberOfCPU < 1) { 261 complain("Illegal number of CPU: " + argument); 262 return 2; // failure 263 } 264 continue; 265 } 266 267 complain("Cannot recognize argument: args[" + argsShift + "]: " + argument); 268 return 2; // failure 269 } 270 271 if ((args.length < argsShift + 1) || (args.length > argsShift + 2)) { 272 complain("Illegal argument(s). Execute:"); 273 complain( 274 " java numeric010 [-verbose] [-performance] " + 275 "[-tolerance:percents] [-CPU:number] matrixSize [threads]"); 276 return 2; // failure 277 } 278 279 int size = Integer.parseInt(args[argsShift]); 280 if ((size < 100) || (size > 10000)) { 281 complain("Matrix size should be 100 to 1000 lines & columns."); 282 return 2; // failure 283 } 284 285 int threads = size; 286 if (args.length >= argsShift + 2) 287 threads = Integer.parseInt(args[argsShift + 1]); 288 if ((threads < 1) || (threads > size)) { 289 complain("Threads number should be 1 to matrix size."); 290 return 2; // failure 291 } 292 if ((size % threads) != 0) { 293 complain("Threads number should evenly divide matrix size."); 294 return 2; // failure 295 } 296 297 print("Preparing A[" + size + "," + size + "]:"); 298 IntegerMatrix intA = new IntegerMatrix(size); 299 IntegerMatrix intAA = new IntegerMatrix(size); 300 LongMatrix longA = new LongMatrix(intA); 301 LongMatrix longAA = new LongMatrix(intA); 302 FloatMatrix floatA = new FloatMatrix(intA); 303 FloatMatrix floatAA = new FloatMatrix(intA); 304 DoubleMatrix doubleA = new DoubleMatrix(intA); 305 DoubleMatrix doubleAA = new DoubleMatrix(intA); 306 println(" done."); 307 308 double elapsed[] = {0, 0}; 309 310 for (int i = 0; i < 2; i++) { 311 double seconds = 312 elapsedTime((i == 0 ? 1 : threads), 313 intA, intAA, 314 longA, longAA, 315 floatA, floatAA, 316 doubleA, doubleAA); 317 elapsed[i] = seconds; 318 319 print("Checking accuracy:"); 320 for (int line = 0; line < size; line++) 321 for (int column = 0; column < size; column++) { 322 if (intAA.value[line][column] != longAA.value[line][column]) { 323 println(""); 324 complain("Test failed:"); 325 complain("Integer and Long results differ at:"); 326 complain(" line=" + line + ", column=" + column); 327 complain(" intAA.value[line][column]=" + intAA.value[line][column]); 328 complain("longAA.value[line][column]=" + longAA.value[line][column]); 329 return 2; // FAILED 330 } 331 if (intAA.value[line][column] != floatAA.value[line][column]) { 332 println(""); 333 complain("Test failed:"); 334 complain("Integer and Float results differ at:"); 335 complain(" line=" + line + ", column=" + column); 336 complain(" intAA.value[line][column]=" + intAA.value[line][column]); 337 complain("floatAA.value[line][column]=" + floatAA.value[line][column]); 338 return 2; // FAILED 339 } 340 if (intAA.value[line][column] != doubleAA.value[line][column]) { 341 println(""); 342 complain("Test failed:"); 343 complain("Integer and Double results differ at:"); 344 complain(" line=" + line + ", column=" + column); 345 complain(" intAA.value[line][column]=" + intAA.value[line][column]); 346 complain("doubleAA.value[line][column]=" + doubleAA.value[line][column]); 347 return 2; // FAILED 348 } 349 } 350 println(" done."); 351 } 352 353 double overallTime = elapsed[0] + elapsed[1]; 354 double averageTime = overallTime / 2; // 2 excutions 355 double averagePerformance = 4 * size * size * (size + size) / averageTime / 1e6; 356 println(""); 357 println("Overall elapsed time: " + overallTime + " seconds."); 358 println("Average elapsed time: " + averageTime + " seconds."); 359 println("Average performance: " + averagePerformance + " MOPS"); 360 361 if (testPerformance) { 362 println(""); 363 print("Checking performance: "); 364 double elapsed1 = elapsed[0]; 365 double elapsedM = elapsed[1] * numberOfCPU; 366 if (elapsed1 > elapsedM * (1 + tolerance / 100)) { 367 println(""); 368 complain("Test failed:"); 369 complain("Single-thread calculation is essentially slower:"); 370 complain("Calculation time elapsed (seconds):"); 371 complain(" single thread: " + elapsed[0]); 372 complain(" multi-threads: " + elapsed[1]); 373 complain(" number of CPU: " + numberOfCPU); 374 complain(" tolerance: " + tolerance + "%"); 375 return 2; // FAILED 376 } 377 println("done."); 378 } 379 380 println("Test passed."); 381 return 0; // PASSED 382 } 383 384 /** 385 * Return time (in seconds) elapsed for calculation of matrix 386 * product <code>A*A</code> with <code>int</code>, <code>long</code>, 387 * <code>float</code>, and <code>double</code> representations. 388 */ elapsedTime(int threads, IntegerMatrix intA, IntegerMatrix intAA, LongMatrix longA, LongMatrix longAA, FloatMatrix floatA, FloatMatrix floatAA, DoubleMatrix doubleA, DoubleMatrix doubleAA)389 private static double elapsedTime(int threads, 390 IntegerMatrix intA, IntegerMatrix intAA, 391 LongMatrix longA, LongMatrix longAA, 392 FloatMatrix floatA, FloatMatrix floatAA, 393 DoubleMatrix doubleA, DoubleMatrix doubleAA) { 394 395 println(""); 396 print("Computing A*A with " + threads + " thread(s):"); 397 long mark1 = System.currentTimeMillis(); 398 intAA.setSquareOf(intA, threads); 399 longAA.setSquareOf(longA, threads); 400 floatAA.setSquareOf(floatA, threads); 401 doubleAA.setSquareOf(doubleA, threads); 402 long mark2 = System.currentTimeMillis(); 403 println(" done."); 404 405 int size = intA.size(); 406 double sec = (mark2 - mark1) / 1000.0; 407 double perf = 4 * size * size * (size + size) / sec; 408 println("Elapsed time: " + sec + " seconds"); 409 println("Performance: " + perf / 1e6 + " MOPS"); 410 411 return sec; 412 } 413 414 /** 415 * Compute <code>A*A</code> for <code>int</code> matrix <code>A</code>. 416 */ 417 private static class IntegerMatrix { 418 volatile int value[][]; 419 420 /** 421 * Number of lines and columns in <code>this</code> square matrix. 422 */ size()423 public int size() { 424 return value.length; 425 } 426 427 /** 428 * New square matrix with random elements. 429 */ IntegerMatrix(int size)430 public IntegerMatrix(int size) { 431 value = new int[size][size]; 432 for (int line = 0; line < size; line++) 433 for (int column = 0; column < size; column++) 434 value[line][column] = 435 Math.round((float) ((1 - 2 * Math.random()) * size)); 436 } 437 438 /** 439 * Assign <code>this</code> matrix with <code>A*A</code>. 440 * 441 * @param threads Split computation into the given number of threads. 442 */ setSquareOf(IntegerMatrix A, int threads)443 public void setSquareOf(IntegerMatrix A, int threads) { 444 if (this.size() != A.size()) 445 throw new IllegalArgumentException( 446 "this.size() != A.size()"); 447 448 if ((size() % threads) != 0) 449 throw new IllegalArgumentException("size()%threads != 0"); 450 int bunch = size() / threads; 451 452 Thread task[] = new Thread[threads]; 453 for (int t = 0; t < threads; t++) { 454 int line0 = bunch * t; 455 MatrixComputer computer = 456 new MatrixComputer(value, A.value, line0, bunch); 457 task[t] = new Thread(computer); 458 } 459 460 for (int t = 0; t < threads; t++) 461 task[t].start(); 462 463 for (int t = 0; t < threads; t++) 464 if (task[t].isAlive()) 465 try { 466 task[t].join(); 467 } catch (InterruptedException exception) { 468 throw new RuntimeException(exception.toString()); 469 } 470 } 471 472 /** 473 * Thread to compute a bunch of lines of matrix square. 474 */ 475 private static class MatrixComputer implements Runnable { 476 private int result[][]; 477 private int source[][]; 478 private int line0; 479 private int bunch; 480 481 /** 482 * Register a task for matrix multiplication. 483 */ MatrixComputer( int result[][], int source[][], int line0, int bunch)484 public MatrixComputer( 485 int result[][], int source[][], int line0, int bunch) { 486 487 this.result = result; // reference to resulting matrix value 488 this.source = source; // reference to matrix to be squared 489 this.line0 = line0; // compute lines from line0 to ... 490 this.bunch = bunch; // number of resulting lines to compute 491 } 492 493 /** 494 * Do execute the task just registered for <code>this</code> thread. 495 */ run()496 public void run() { 497 int line1 = line0 + bunch; 498 int size = result.length; 499 for (int line = line0; line < line1; line++) 500 for (int column = 0; column < size; column++) { 501 int sum = 0; 502 for (int i = 0; i < size; i++) 503 sum += source[line][i] * source[i][column]; 504 result[line][column] = sum; 505 } 506 } 507 508 } 509 510 } 511 512 /** 513 * Compute <code>A*A</code> for <code>long</code> matrix <code>A</code>. 514 */ 515 private static class LongMatrix { 516 volatile long value[][]; 517 518 /** 519 * Number of lines and columns in <code>this</code> square matrix. 520 */ size()521 public int size() { 522 return value.length; 523 } 524 525 526 /** 527 * New square matrix with the given integer elements. 528 */ LongMatrix(IntegerMatrix A)529 public LongMatrix(IntegerMatrix A) { 530 int size = A.size(); 531 value = new long[size][size]; 532 for (int line = 0; line < size; line++) 533 for (int column = 0; column < size; column++) 534 value[line][column] = A.value[line][column]; 535 } 536 537 /** 538 * Assign <code>this</code> matrix with <code>A*A</code>. 539 * 540 * @param threads Split computation into the given number of threads. 541 */ setSquareOf(LongMatrix A, int threads)542 public void setSquareOf(LongMatrix A, int threads) { 543 if (this.size() != A.size()) 544 throw new IllegalArgumentException( 545 "this.size() != A.size()"); 546 547 if ((size() % threads) != 0) 548 throw new IllegalArgumentException("size()%threads != 0"); 549 int bunch = size() / threads; 550 551 Thread task[] = new Thread[threads]; 552 for (int t = 0; t < threads; t++) { 553 int line0 = bunch * t; 554 MatrixComputer computer = 555 new MatrixComputer(value, A.value, line0, bunch); 556 task[t] = new Thread(computer); 557 } 558 559 for (int t = 0; t < threads; t++) 560 task[t].start(); 561 562 for (int t = 0; t < threads; t++) 563 if (task[t].isAlive()) 564 try { 565 task[t].join(); 566 } catch (InterruptedException exception) { 567 throw new RuntimeException(exception.toString()); 568 } 569 } 570 571 /** 572 * Thread to compute a bunch of lines of matrix square. 573 */ 574 private static class MatrixComputer implements Runnable { 575 private long result[][]; 576 private long source[][]; 577 private int line0; 578 private int bunch; 579 580 /** 581 * Register a task for matrix multiplication. 582 */ MatrixComputer( long result[][], long source[][], int line0, int bunch)583 public MatrixComputer( 584 long result[][], long source[][], int line0, int bunch) { 585 586 this.result = result; // reference to resulting matrix value 587 this.source = source; // reference to matrix to be squared 588 this.line0 = line0; // compute lines from line0 to ... 589 this.bunch = bunch; // number of resulting lines to compute 590 } 591 592 /** 593 * Do execute the task just registered for <code>this</code> thread. 594 */ run()595 public void run() { 596 int line1 = line0 + bunch; 597 int size = result.length; 598 for (int line = line0; line < line1; line++) 599 for (int column = 0; column < size; column++) { 600 long sum = 0; 601 for (int i = 0; i < size; i++) 602 sum += source[line][i] * source[i][column]; 603 result[line][column] = sum; 604 } 605 } 606 607 } 608 609 } 610 611 /** 612 * Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>. 613 */ 614 private static class FloatMatrix { 615 volatile float value[][]; 616 617 /** 618 * Number of lines and columns in <code>this</code> square matrix. 619 */ size()620 public int size() { 621 return value.length; 622 } 623 624 625 /** 626 * New square matrix with the given integer elements. 627 */ FloatMatrix(IntegerMatrix A)628 public FloatMatrix(IntegerMatrix A) { 629 int size = A.size(); 630 value = new float[size][size]; 631 for (int line = 0; line < size; line++) 632 for (int column = 0; column < size; column++) 633 value[line][column] = A.value[line][column]; 634 } 635 636 /** 637 * Assign <code>this</code> matrix with <code>A*A</code>. 638 * 639 * @param threads Split computation into the given number of threads. 640 */ setSquareOf(FloatMatrix A, int threads)641 public void setSquareOf(FloatMatrix A, int threads) { 642 if (this.size() != A.size()) 643 throw new IllegalArgumentException( 644 "this.size() != A.size()"); 645 646 if ((size() % threads) != 0) 647 throw new IllegalArgumentException("size()%threads != 0"); 648 int bunch = size() / threads; 649 650 Thread task[] = new Thread[threads]; 651 for (int t = 0; t < threads; t++) { 652 int line0 = bunch * t; 653 MatrixComputer computer = 654 new MatrixComputer(value, A.value, line0, bunch); 655 task[t] = new Thread(computer); 656 } 657 658 for (int t = 0; t < threads; t++) 659 task[t].start(); 660 661 for (int t = 0; t < threads; t++) 662 if (task[t].isAlive()) 663 try { 664 task[t].join(); 665 } catch (InterruptedException exception) { 666 throw new RuntimeException(exception.toString()); 667 } 668 } 669 670 /** 671 * Thread to compute a bunch of lines of matrix square. 672 */ 673 private static class MatrixComputer implements Runnable { 674 private float result[][]; 675 private float source[][]; 676 private int line0; 677 private int bunch; 678 679 /** 680 * Register a task for matrix multiplication. 681 */ MatrixComputer( float result[][], float source[][], int line0, int bunch)682 public MatrixComputer( 683 float result[][], float source[][], int line0, int bunch) { 684 685 this.result = result; // reference to resulting matrix value 686 this.source = source; // reference to matrix to be squared 687 this.line0 = line0; // compute lines from line0 to ... 688 this.bunch = bunch; // number of resulting lines to compute 689 } 690 691 /** 692 * Do execute the task just registered for <code>this</code> thread. 693 */ run()694 public void run() { 695 int line1 = line0 + bunch; 696 int size = result.length; 697 for (int line = line0; line < line1; line++) 698 for (int column = 0; column < size; column++) { 699 float sum = 0; 700 for (int i = 0; i < size; i++) 701 sum += source[line][i] * source[i][column]; 702 result[line][column] = sum; 703 } 704 } 705 706 } 707 708 } 709 710 /** 711 * Compute <code>A*A</code> for <code>float</code> matrix <code>A</code>. 712 */ 713 private static class DoubleMatrix { 714 volatile double value[][]; 715 716 /** 717 * Number of lines and columns in <code>this</code> square matrix. 718 */ size()719 public int size() { 720 return value.length; 721 } 722 723 724 /** 725 * New square matrix with the given integer elements. 726 */ DoubleMatrix(IntegerMatrix A)727 public DoubleMatrix(IntegerMatrix A) { 728 int size = A.size(); 729 value = new double[size][size]; 730 for (int line = 0; line < size; line++) 731 for (int column = 0; column < size; column++) 732 value[line][column] = A.value[line][column]; 733 } 734 735 /** 736 * Assign <code>this</code> matrix with <code>A*A</code>. 737 * 738 * @param threads Split computation into the given number of threads. 739 */ setSquareOf(DoubleMatrix A, int threads)740 public void setSquareOf(DoubleMatrix A, int threads) { 741 if (this.size() != A.size()) 742 throw new IllegalArgumentException( 743 "this.size() != A.size()"); 744 745 if ((size() % threads) != 0) 746 throw new IllegalArgumentException("size()%threads != 0"); 747 int bunch = size() / threads; 748 749 Thread task[] = new Thread[threads]; 750 for (int t = 0; t < threads; t++) { 751 int line0 = bunch * t; 752 MatrixComputer computer = 753 new MatrixComputer(value, A.value, line0, bunch); 754 task[t] = new Thread(computer); 755 } 756 757 for (int t = 0; t < threads; t++) 758 task[t].start(); 759 760 for (int t = 0; t < threads; t++) 761 if (task[t].isAlive()) 762 try { 763 task[t].join(); 764 } catch (InterruptedException exception) { 765 throw new RuntimeException(exception.toString()); 766 } 767 } 768 769 /** 770 * Thread to compute a bunch of lines of matrix square. 771 */ 772 private static class MatrixComputer implements Runnable { 773 private double result[][]; 774 private double source[][]; 775 private int line0; 776 private int bunch; 777 778 /** 779 * Register a task for matrix multiplication. 780 */ MatrixComputer( double result[][], double source[][], int line0, int bunch)781 public MatrixComputer( 782 double result[][], double source[][], int line0, int bunch) { 783 784 this.result = result; // reference to resulting matrix value 785 this.source = source; // reference to matrix to be squared 786 this.line0 = line0; // compute lines from line0 to ... 787 this.bunch = bunch; // number of resulting lines to compute 788 } 789 790 /** 791 * Do execute the task just registered for <code>this</code> thread. 792 */ run()793 public void run() { 794 int line1 = line0 + bunch; 795 int size = result.length; 796 for (int line = line0; line < line1; line++) 797 for (int column = 0; column < size; column++) { 798 double sum = 0; 799 for (int i = 0; i < size; i++) 800 sum += source[line][i] * source[i][column]; 801 result[line][column] = sum; 802 } 803 } 804 805 } 806 807 } 808 809 } 810