From: Andy Ayers
Date: Thu, 7 Jan 2016 17:13:50 +0000 (-0800)
Subject: Add SciMark benchmark
X-Git-Tag: accepted/tizen/base/20180629.140029~5893^2
X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf72a4f2b0c8937102d1b791755c1ae5b0da7cad;p=platform%2Fupstream%2Fcoreclr.git
Add SciMark benchmark
3rd party attributions retained in file header comments.
---
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/CommandLine.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/CommandLine.cs
new file mode 100644
index 0000000..8ee71c7
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/CommandLine.cs
@@ -0,0 +1,103 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ ///
+ /// SciMark2: A Java numerical benchmark measuring performance
+ /// of computational kernels for FFTs, Monte Carlo simulation,
+ /// sparse matrix computations, Jacobi SOR, and dense LU matrix
+ /// factorizations.
+ ///
+
+ public class CommandLine
+ {
+ ///
+ /// Benchmark 5 kernels with individual Mflops.
+ /// "results[0]" has the average Mflop rate.
+ ///
+ public static int Main(System.String[] args)
+ {
+#if DEBUG
+ double min_time = Constants.RESOLUTION_TINY;
+#else
+ double min_time = Constants.RESOLUTION_DEFAULT;
+#endif
+
+ int FFT_size = Constants.FFT_SIZE;
+ int SOR_size = Constants.SOR_SIZE;
+ int Sparse_size_M = Constants.SPARSE_SIZE_M;
+ int Sparse_size_nz = Constants.SPARSE_SIZE_nz;
+ int LU_size = Constants.LU_SIZE;
+
+ // look for runtime options
+ if (args.Length > 0)
+ {
+ if (args[0].ToUpper().Equals("-h") ||
+ args[0].ToUpper().Equals("-help"))
+ {
+ Console.WriteLine("Usage: [-large] [iterations]");
+ return -1;
+ }
+
+ int current_arg = 0;
+ if (args[current_arg].ToUpper().Equals("-LARGE"))
+ {
+ FFT_size = Constants.LG_FFT_SIZE;
+ SOR_size = Constants.LG_SOR_SIZE;
+ Sparse_size_M = Constants.LG_SPARSE_SIZE_M;
+ Sparse_size_nz = Constants.LG_SPARSE_SIZE_nz;
+ LU_size = Constants.LG_LU_SIZE;
+
+ current_arg++;
+ }
+
+ if (args.Length > current_arg)
+ min_time = Double.Parse(args[current_arg]);
+ }
+ Console.WriteLine("** **");
+ Console.WriteLine("** SciMark2a Numeric Benchmark, see http://math.nist.gov/scimark **");
+ Console.WriteLine("** **");
+
+ // run the benchmark
+ double[] res = new double[6];
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+
+ Console.WriteLine("Mininum running time = {0} seconds", min_time);
+
+ res[1] = kernel.measureFFT(FFT_size, min_time, R);
+
+ res[2] = kernel.measureSOR(SOR_size, min_time, R);
+
+ res[3] = kernel.measureMonteCarlo(min_time, R);
+
+ res[4] = kernel.measureSparseMatmult(Sparse_size_M, Sparse_size_nz, min_time, R);
+
+ res[5] = kernel.measureLU(LU_size, min_time, R);
+
+ res[0] = (res[1] + res[2] + res[3] + res[4] + res[5]) / 5;
+
+ // print out results
+ Console.WriteLine();
+ Console.WriteLine("Composite Score: {0:F2} MFlops", res[0]);
+ Console.WriteLine("FFT : {0} - ({1})", res[1] == 0.0 ? "ERROR, INVALID NUMERICAL RESULT!" : res[1].ToString("F2"), FFT_size);
+ Console.WriteLine("SOR : {1:F2} - ({0}x{0})", SOR_size, res[2]);
+ Console.WriteLine("Monte Carlo : {0:F2}", res[3]);
+ Console.WriteLine("Sparse MatMult : {2:F2} - (N={0}, nz={1})", Sparse_size_M, Sparse_size_nz, res[4]);
+ Console.WriteLine("LU : {1} - ({0}x{0})", LU_size, res[1] == 0.0 ? "ERROR, INVALID NUMERICAL RESULT!" : res[5].ToString("F2"));
+
+ return 100;
+ }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/Constants.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/Constants.cs
new file mode 100644
index 0000000..a99bce9
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/Constants.cs
@@ -0,0 +1,48 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+namespace SciMark2
+{
+ public class Constants
+ {
+ public const double RESOLUTION_DEFAULT = 2.0; /*secs*/
+ public const double RESOLUTION_TINY = 0.02; /*secs*/
+ public const int RANDOM_SEED = 101010;
+
+ // default: small (cache-contained) problem sizes
+ //
+ public const int FFT_SIZE = 1024; // must be a power of two
+ public const int SOR_SIZE = 100; // NxN grid
+ public const int SPARSE_SIZE_M = 1000;
+ public const int SPARSE_SIZE_nz = 5000;
+ public const int LU_SIZE = 100;
+
+ // large (out-of-cache) problem sizes
+ //
+ public const int LG_FFT_SIZE = 1048576; // must be a power of two
+ public const int LG_SOR_SIZE = 1000; // NxN grid
+ public const int LG_SPARSE_SIZE_M = 100000;
+ public const int LG_SPARSE_SIZE_nz = 1000000;
+ public const int LG_LU_SIZE = 1000;
+
+ // tiny problem sizes (used to mainly to preload network classes
+ // for applet, so that network download times
+ // are factored out of benchmark.)
+ //
+ public const int TINY_FFT_SIZE = 16; // must be a power of two
+ public const int TINY_SOR_SIZE = 10; // NxN grid
+ public const int TINY_SPARSE_SIZE_M = 10;
+ public const int TINY_SPARSE_SIZE_N = 10;
+ public const int TINY_SPARSE_SIZE_nz = 50;
+ public const int TINY_LU_SIZE = 10;
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/FFT.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/FFT.cs
new file mode 100644
index 0000000..df32c42
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/FFT.cs
@@ -0,0 +1,219 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ /// Computes FFT's of complex, double precision data where n is an integer power of 2.
+ /// This appears to be slower than the Radix2 method,
+ /// but the code is smaller and simpler, and it requires no extra storage.
+ ///
+ ///
+ ///
+ ///
+ /// Bruce R. Miller bruce.miller@nist.gov,
+ /// Derived from GSL (Gnu Scientific Library),
+ /// GSL's FFT Code by Brian Gough bjg@vvv.lanl.gov
+ ///
+
+ public class FFT
+ {
+ public static double num_flops(int N)
+ {
+ double Nd = (double)N;
+ double logN = (double)log2(N);
+
+ return (5.0 * Nd - 2) * logN + 2 * (Nd + 1);
+ }
+
+
+ ///
+ /// Compute Fast Fourier Transform of (complex) data, in place.
+ ///
+ public static void transform(double[] data)
+ {
+ transform_internal(data, -1);
+ }
+
+ ///
+ /// Compute Inverse Fast Fourier Transform of (complex) data, in place.
+ ///
+ public static void inverse(double[] data)
+ {
+ transform_internal(data, +1);
+ // Normalize
+ int nd = data.Length;
+ int n = nd / 2;
+ double norm = 1 / ((double)n);
+ for (int i = 0; i < nd; i++)
+ data[i] *= norm;
+ }
+
+ ///
+ /// Accuracy check on FFT of data. Make a copy of data, Compute the FFT, then
+ /// the inverse and compare to the original. Returns the rms difference.
+ ///
+ public static double test(double[] data)
+ {
+ int nd = data.Length;
+ // Make duplicate for comparison
+ double[] copy = new double[nd];
+ Array.Copy(data, 0, copy, 0, nd);
+ // Transform & invert
+ transform(data);
+ inverse(data);
+ // Compute RMS difference.
+ double diff = 0.0;
+ for (int i = 0; i < nd; i++)
+ {
+ double d = data[i] - copy[i];
+ diff += d * d;
+ }
+ return Math.Sqrt(diff / nd);
+ }
+
+ ///
+ /// Make a random array of n (complex) elements.
+ ///
+ public static double[] makeRandom(int n)
+ {
+ int nd = 2 * n;
+ double[] data = new double[nd];
+ System.Random r = new System.Random();
+ for (int i = 0; i < nd; i++)
+ data[i] = r.NextDouble();
+ return data;
+ }
+
+ protected internal static int log2(int n)
+ {
+ int log = 0;
+ for (int k = 1; k < n; k *= 2, log++)
+ ;
+ if (n != (1 << log))
+ throw new Exception("FFT: Data length is not a power of 2!: " + n);
+ return log;
+ }
+
+ protected internal static void transform_internal(double[] data, int direction)
+ {
+ if (data.Length == 0)
+ return;
+ int n = data.Length / 2;
+ if (n == 1)
+ return;
+ // Identity operation!
+ int logn = log2(n);
+
+ /* bit reverse the input data for decimation in time algorithm */
+ bitreverse(data);
+
+ /* apply fft recursion */
+ /* this loop executed log2(N) times */
+ for (int bit = 0, dual = 1; bit < logn; bit++, dual *= 2)
+ {
+ double w_real = 1.0;
+ double w_imag = 0.0;
+
+ double theta = 2.0 * direction * Math.PI / (2.0 * (double)dual);
+ double s = Math.Sin(theta);
+ double t = Math.Sin(theta / 2.0);
+ double s2 = 2.0 * t * t;
+
+ /* a = 0 */
+ for (int b = 0; b < n; b += 2 * dual)
+ {
+ int i = 2 * b;
+ int j = 2 * (b + dual);
+
+ double wd_real = data[j];
+ double wd_imag = data[j + 1];
+
+ data[j] = data[i] - wd_real;
+ data[j + 1] = data[i + 1] - wd_imag;
+ data[i] += wd_real;
+ data[i + 1] += wd_imag;
+ }
+
+ /* a = 1 .. (dual-1) */
+ for (int a = 1; a < dual; a++)
+ {
+ /* trignometric recurrence for w-> exp(i theta) w */
+ {
+ double tmp_real = w_real - s * w_imag - s2 * w_real;
+ double tmp_imag = w_imag + s * w_real - s2 * w_imag;
+ w_real = tmp_real;
+ w_imag = tmp_imag;
+ }
+ for (int b = 0; b < n; b += 2 * dual)
+ {
+ int i = 2 * (b + a);
+ int j = 2 * (b + a + dual);
+
+ double z1_real = data[j];
+ double z1_imag = data[j + 1];
+
+ double wd_real = w_real * z1_real - w_imag * z1_imag;
+ double wd_imag = w_real * z1_imag + w_imag * z1_real;
+
+ data[j] = data[i] - wd_real;
+ data[j + 1] = data[i + 1] - wd_imag;
+ data[i] += wd_real;
+ data[i + 1] += wd_imag;
+ }
+ }
+ }
+ }
+
+
+ protected internal static void bitreverse(double[] data)
+ {
+ /* This is the Goldrader bit-reversal algorithm */
+ int n = data.Length / 2;
+ int nm1 = n - 1;
+ int i = 0;
+ int j = 0;
+ for (; i < nm1; i++)
+ {
+ //int ii = 2*i;
+ int ii = i << 1;
+
+ //int jj = 2*j;
+ int jj = j << 1;
+
+ //int k = n / 2 ;
+ int k = n >> 1;
+
+ if (i < j)
+ {
+ double tmp_real = data[ii];
+ double tmp_imag = data[ii + 1];
+ data[ii] = data[jj];
+ data[ii + 1] = data[jj + 1];
+ data[jj] = tmp_real;
+ data[jj + 1] = tmp_imag;
+ }
+
+ while (k <= j)
+ {
+ //j = j - k ;
+ j -= k;
+
+ //k = k / 2 ;
+ k >>= 1;
+ }
+ j += k;
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/LU.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/LU.cs
new file mode 100644
index 0000000..481922a
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/LU.cs
@@ -0,0 +1,268 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ ///
+ /// LU matrix factorization. (Based on TNT implementation.)
+ /// Decomposes a matrix A into a triangular lower triangular
+ /// factor (L) and an upper triangular factor (U) such that
+ /// A = L*U. By convnetion, the main diagonal of L consists
+ /// of 1's so that L and U can be stored compactly in
+ /// a NxN matrix.
+ ///
+ public class LU
+ {
+ private double[][] _LU;
+ private int[] _pivot;
+
+ ///
+ /// Returns a copy of the compact LU factorization.
+ /// (useful mainly for debugging.)
+ ///
+ ///
+ ///
+ /// the compact LU factorization. The U factor
+ /// is stored in the upper triangular portion, and the L
+ /// factor is stored in the lower triangular portion.
+ /// The main diagonal of L consists (by convention) of
+ /// ones, and is not explicitly stored.
+ ///
+ public static double num_flops(int N)
+ {
+ // rougly 2/3*N^3
+
+ double Nd = (double)N;
+
+ return (2.0 * Nd * Nd * Nd / 3.0);
+ }
+
+ protected internal static double[] new_copy(double[] x)
+ {
+ double[] T = new double[x.Length];
+ x.CopyTo(T, 0);
+ return T;
+ }
+
+
+ protected internal static double[][] new_copy(double[][] A)
+ {
+ int M = A.Length;
+ int N = A[0].Length;
+
+ double[][] T = new double[M][];
+ for (int i = 0; i < M; i++)
+ {
+ T[i] = new double[N];
+ }
+
+ for (int i = 0; i < M; i++)
+ {
+ A[i].CopyTo(T[i], 0);
+ }
+
+ return T;
+ }
+
+
+
+ public static int[] new_copy(int[] x)
+ {
+ int[] T = new int[x.Length];
+ x.CopyTo(T, 0);
+ return T;
+ }
+
+ protected internal static void insert_copy(double[][] B, double[][] A)
+ {
+ for (int i = 0; i < A.Length; i++)
+ {
+ A[i].CopyTo(B[i], 0);
+ }
+ }
+
+ ///
+ /// Initalize LU factorization from matrix.
+ ///
+ ///
+ /// (in) the matrix to associate with this factorization.
+ ///
+ ///
+ public LU(double[][] A)
+ {
+ _LU = new_copy(A);
+ _pivot = new int[A.Length];
+
+ factor(_LU, _pivot);
+ }
+
+ ///
+ /// Solve a linear system, with pre-computed factorization.
+ ///
+ ///
+ /// (in) the right-hand side.
+ ///
+ ///
+ /// solution vector.
+ ///
+ public virtual double[] solve(double[] b)
+ {
+ double[] x = new_copy(b);
+
+ solve(_LU, _pivot, x);
+ return x;
+ }
+
+
+ ///
+ /// LU factorization (in place).
+ ///
+ ///
+ /// (in/out) On input, the matrix to be factored.
+ /// On output, the compact LU factorization.
+ ///
+ ///
+ /// (out) The pivot vector records the
+ /// reordering of the rows of A during factorization.
+ ///
+ ///
+ /// 0, if OK, nozero value, othewise.
+ ///
+ public static int factor(double[][] A, int[] pivot)
+ {
+ int N = A.Length;
+ int M = A[0].Length;
+
+ int minMN = Math.Min(M, N);
+
+ for (int j = 0; j < minMN; j++)
+ {
+ // find pivot in column j and test for singularity.
+ int jp = j;
+
+ double t = Math.Abs(A[j][j]);
+ for (int i = j + 1; i < M; i++)
+ {
+ double ab = Math.Abs(A[i][j]);
+ if (ab > t)
+ {
+ jp = i;
+ t = ab;
+ }
+ }
+
+ pivot[j] = jp;
+
+ // jp now has the index of maximum element
+ // of column j, below the diagonal
+ if (A[jp][j] == 0)
+ return 1;
+
+ // factorization failed because of zero pivot
+ if (jp != j)
+ {
+ // swap rows j and jp
+ double[] tA = A[j];
+ A[j] = A[jp];
+ A[jp] = tA;
+ }
+
+ if (j < M - 1)
+ {
+ // compute elements j+1:M of jth column
+ // note A(j,j), was A(jp,p) previously which was
+ // guarranteed not to be zero (Label #1)
+ //
+ double recp = 1.0 / A[j][j];
+
+ for (int k = j + 1; k < M; k++)
+ A[k][j] *= recp;
+ }
+
+ if (j < minMN - 1)
+ {
+ // rank-1 update to trailing submatrix: E = E - x*y;
+ //
+ // E is the region A(j+1:M, j+1:N)
+ // x is the column vector A(j+1:M,j)
+ // y is row vector A(j,j+1:N)
+ for (int ii = j + 1; ii < M; ii++)
+ {
+ double[] Aii = A[ii];
+ double[] Aj = A[j];
+ double AiiJ = Aii[j];
+ for (int jj = j + 1; jj < N; jj++)
+ Aii[jj] -= AiiJ * Aj[jj];
+ }
+ }
+ }
+
+ return 0;
+ }
+
+
+ /// Solve a linear system, using a prefactored matrix
+ /// in LU form.
+ ///
+ /// (in) the factored matrix in LU form.
+ ///
+ /// (in) the pivot vector which lists
+ /// the reordering used during the factorization
+ /// stage.
+ ///
+ /// (in/out) On input, the right-hand side.
+ /// On output, the solution vector.
+ ///
+ ///
+ public static void solve(double[][] A, int[] pvt, double[] b)
+ {
+ int M = A.Length;
+ int N = A[0].Length;
+ int ii = 0;
+
+ for (int i = 0; i < M; i++)
+ {
+ int ip = pvt[i];
+ double sum = b[ip];
+
+ b[ip] = b[i];
+ if (ii == 0)
+ {
+ for (int j = ii; j < i; j++)
+ {
+ sum -= A[i][j] * b[j];
+ }
+ }
+ else
+ {
+ if (sum == 0.0)
+ {
+ ii = i;
+ }
+ }
+ b[i] = sum;
+ }
+
+ for (int i = N - 1; i >= 0; i--)
+ {
+ double sum = b[i];
+ for (int j = i + 1; j < N; j++)
+ {
+ sum -= A[i][j] * b[j];
+ }
+ b[i] = sum / A[i][i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/MonteCarlo.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/MonteCarlo.cs
new file mode 100644
index 0000000..0e5adce
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/MonteCarlo.cs
@@ -0,0 +1,69 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ /// Estimate Pi by approximating the area of a circle.
+ /// How: generate N random numbers in the unit square, (0,0) to (1,1)
+ /// and see how are within a radius of 1 or less, i.e.
+ ///
+ /// sqrt(x^2 + y^2) < r
+ ///
+ /// since the radius is 1.0, we can square both sides
+ /// and avoid a sqrt() computation:
+ ///
+ /// x^2 + y^2 <= 1.0
+ ///
+ /// this area under the curve is (Pi * r^2)/ 4.0,
+ /// and the area of the unit of square is 1.0,
+ /// so Pi can be approximated by
+ ///
+ /// # points with x^2+y^2 < 1
+ /// Pi =~ -------------------------- * 4.0
+ /// total # points
+ ///
+ ///
+
+ public class MonteCarlo
+ {
+ internal const int SEED = 113;
+
+ public static double num_flops(int Num_samples)
+ {
+ // 3 flops in x^2+y^2 and 1 flop in random routine
+
+ return ((double)Num_samples) * 4.0;
+ }
+
+
+
+ public static double integrate(int Num_samples)
+ {
+ SciMark2.Random R = new SciMark2.Random(SEED);
+
+
+ int under_curve = 0;
+ for (int count = 0; count < Num_samples; count++)
+ {
+ double x = R.nextDouble();
+ double y = R.nextDouble();
+
+ if (x * x + y * y <= 1.0)
+ under_curve++;
+ }
+
+ return ((double)under_curve / Num_samples) * 4.0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/Random.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/Random.cs
new file mode 100644
index 0000000..b65ec32
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/Random.cs
@@ -0,0 +1,302 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SciMark2
+{
+ /* Random.java based on Java Numerical Toolkit (JNT) Random.UniformSequence
+ class. We do not use Java's own java.util.Random so that we can compare
+ results with equivalent C and Fortran coces.*/
+
+ public class Random
+ {
+ /*------------------------------------------------------------------------------
+ CLASS VARIABLES
+ ------------------------------------------------------------------------------ */
+
+ internal int seed = 0;
+
+ private int[] _m;
+ private int _i = 4;
+ private int _j = 16;
+
+ private const int mdig = 32;
+ private const int one = 1;
+ private int _m1;
+ private int _m2;
+
+ private double _dm1;
+
+ private bool _haveRange = false;
+ private double _left = 0.0;
+ private double _right = 1.0;
+ private double _width = 1.0;
+
+
+ /* ------------------------------------------------------------------------------
+ CONSTRUCTORS
+ ------------------------------------------------------------------------------ */
+
+ ///
+ /// Initializes a sequence of uniformly distributed quasi random numbers with a
+ /// seed based on the system clock.
+ ///
+ public Random()
+ {
+ initialize((int)System.DateTime.Now.Ticks);
+ }
+
+ ///
+ /// Initializes a sequence of uniformly distributed quasi random numbers on a
+ /// given half-open interval [left,right) with a seed based on the system
+ /// clock.
+ ///
+ /// (double)
+ /// The left endpoint of the half-open interval [left,right).
+ ///
+ /// (double)
+ /// The right endpoint of the half-open interval [left,right).
+ ///
+ public Random(double left, double right)
+ {
+ initialize((int)System.DateTime.Now.Ticks);
+ _left = left;
+ _right = right;
+ _width = right - left;
+ _haveRange = true;
+ }
+
+ ///
+ /// Initializes a sequence of uniformly distributed quasi random numbers with a
+ /// given seed.
+ ///
+ /// (int)
+ /// The seed of the random number generator. Two sequences with the same
+ /// seed will be identical.
+ ///
+ public Random(int seed)
+ {
+ initialize(seed);
+ }
+
+ /// Initializes a sequence of uniformly distributed quasi random numbers
+ /// with a given seed on a given half-open interval [left,right).
+ ///
+ /// (int)
+ /// The seed of the random number generator. Two sequences with the same
+ /// seed will be identical.
+ ///
+ /// (double)
+ /// The left endpoint of the half-open interval [left,right).
+ ///
+ /// (double)
+ /// The right endpoint of the half-open interval [left,right).
+ ///
+ public Random(int seed, double left, double right)
+ {
+ initialize(seed);
+ _left = left;
+ _right = right;
+ _width = right - left;
+ _haveRange = true;
+ }
+
+ /* ------------------------------------------------------------------------------
+ PUBLIC METHODS
+ ------------------------------------------------------------------------------ */
+
+ ///
+ /// Returns the next random number in the sequence.
+ ///
+ public double nextDouble()
+ {
+ int k;
+
+ k = _m[_i] - _m[_j];
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+
+ if (_haveRange)
+ return _left + _dm1 * (double)k * _width;
+ else
+ return _dm1 * (double)k;
+ }
+
+ ///
+ /// Returns the next N random numbers in the sequence, as
+ /// a vector.
+ ///
+ public void nextDoubles(double[] x)
+ {
+ int N = x.Length;
+ int remainder = N & 3;
+
+ if (_haveRange)
+ {
+ for (int count = 0; count < N; count++)
+ {
+ int k = _m[_i] - _m[_j];
+
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+
+ x[count] = _left + _dm1 * (double)k * _width;
+ }
+ }
+ else
+ {
+ for (int count = 0; count < remainder; count++)
+ {
+ int k = _m[_i] - _m[_j];
+
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+
+
+ x[count] = _dm1 * (double)k;
+ }
+
+ for (int count = remainder; count < N; count += 4)
+ {
+ int k = _m[_i] - _m[_j];
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+ x[count] = _dm1 * (double)k;
+
+
+ k = _m[_i] - _m[_j];
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+ x[count + 1] = _dm1 * (double)k;
+
+
+ k = _m[_i] - _m[_j];
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+ x[count + 2] = _dm1 * (double)k;
+
+
+ k = _m[_i] - _m[_j];
+ if (_i == 0)
+ _i = 16;
+ else
+ _i--;
+ if (k < 0)
+ k += _m1;
+ _m[_j] = k;
+ if (_j == 0)
+ _j = 16;
+ else
+ _j--;
+ x[count + 3] = _dm1 * (double)k;
+ }
+ }
+ }
+
+ /*----------------------------------------------------------------------------
+ PRIVATE METHODS
+ ------------------------------------------------------------------------ */
+
+ private void initialize(int seed)
+ {
+ // First the initialization of the member variables;
+ _m1 = (one << mdig - 2) + ((one << mdig - 2) - one);
+ _m2 = one << mdig / 2;
+ _dm1 = 1.0 / (double)_m1;
+
+ int jseed, k0, k1, j0, j1, iloop;
+
+ this.seed = seed;
+
+ _m = new int[17];
+
+ jseed = System.Math.Min(System.Math.Abs(seed), _m1);
+ if (jseed % 2 == 0)
+ --jseed;
+ k0 = 9069 % _m2;
+ k1 = 9069 / _m2;
+ j0 = jseed % _m2;
+ j1 = jseed / _m2;
+ for (iloop = 0; iloop < 17; ++iloop)
+ {
+ jseed = j0 * k0;
+ j1 = (jseed / _m2 + j0 * k1 + j1 * k0) % (_m2 / 2);
+ j0 = jseed % _m2;
+ _m[iloop] = j0 + _m2 * j1;
+ }
+ _i = 4;
+ _j = 16;
+ }
+ }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/SOR.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/SOR.cs
new file mode 100644
index 0000000..bc33c16
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/SOR.cs
@@ -0,0 +1,53 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ public class SOR
+ {
+ public static double num_flops(int M, int N, int num_iterations)
+ {
+ double Md = (double)M;
+ double Nd = (double)N;
+ double num_iterD = (double)num_iterations;
+
+ return (Md - 1) * (Nd - 1) * num_iterD * 6.0;
+ }
+
+ public static void execute(double omega, double[][] G, int num_iterations)
+ {
+ int M = G.Length;
+ int N = G[0].Length;
+
+ double omega_over_four = omega * 0.25;
+ double one_minus_omega = 1.0 - omega;
+
+ // update interior points
+ //
+ int Mm1 = M - 1;
+ int Nm1 = N - 1;
+ for (int p = 0; p < num_iterations; p++)
+ {
+ for (int i = 1; i < Mm1; i++)
+ {
+ double[] Gi = G[i];
+ double[] Gim1 = G[i - 1];
+ double[] Gip1 = G[i + 1];
+ for (int j = 1; j < Nm1; j++)
+ Gi[j] = omega_over_four * (Gim1[j] + Gip1[j] + Gi[j - 1] + Gi[j + 1]) + one_minus_omega * Gi[j];
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/SciMark.csproj b/tests/src/JIT/Performance/CodeQuality/SciMark/SciMark.csproj
new file mode 100644
index 0000000..6583073
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/SciMark.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 2.0
+ {95DFC527-4DC1-495E-97D7-E94EE1F7140D}
+ Exe
+ Properties
+ 512
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages
+ ..\..\
+ 7a9bfb7d
+ SciMark
+
+
+
+
+
+ pdbonly
+ true
+
+
+
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(JitPackagesConfigFileDirectory)benchmark\project.json
+ $(JitPackagesConfigFileDirectory)benchmark\project.lock.json
+
+
+
+
+
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/SparseCompRow.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/SparseCompRow.cs
new file mode 100644
index 0000000..02bdea6
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/SparseCompRow.cs
@@ -0,0 +1,56 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ public class SparseCompRow
+ {
+ // multiple iterations used to make kernel
+ // have roughly same granulairty as other
+ // Scimark kernels
+ public static double num_flops(int N, int nz, int num_iterations)
+ {
+ /* Note that if nz does not divide N evenly, then the
+ actual number of nonzeros used is adjusted slightly.
+ */
+ int actual_nz = (nz / N) * N;
+ return ((double)actual_nz) * 2.0 * ((double)num_iterations);
+ }
+
+ ///
+ /// computes a matrix-vector multiply with a sparse matrix
+ /// held in compress-row format. If the size of the matrix
+ /// in MxN with nz nonzeros, then the val[] is the nz nonzeros,
+ /// with its ith entry in column col[i]. The integer vector row[]
+ /// is of size M+1 and row[i] points to the begining of the
+ /// ith row in col[].
+ public static void matmult(double[] y, double[] val, int[] row, int[] col, double[] x, int NUM_ITERATIONS)
+ {
+ int M = row.Length - 1;
+
+ for (int reps = 0; reps < NUM_ITERATIONS; reps++)
+ {
+ for (int r = 0; r < M; r++)
+ {
+ double sum = 0.0;
+ int rowR = row[r];
+ int rowRp1 = row[r + 1];
+ for (int i = rowR; i < rowRp1; i++)
+ sum += x[col[i]] * val[i];
+ y[r] = sum;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/Stopwatch.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/Stopwatch.cs
new file mode 100644
index 0000000..b82dd5d
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/Stopwatch.cs
@@ -0,0 +1,109 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using System;
+
+namespace SciMark2
+{
+ ///
+ /// Provides a stopwatch to measure elapsed time.
+ ///
+ ///
+ /// Roldan Pozo
+ ///
+ ///
+ /// 14 October 1997, revised 1999-04-24
+ ///
+ ///
+ public class Stopwatch
+ {
+ private bool _running;
+ private double _last_time;
+ private double _total;
+
+ ///
+ /// R
+ /// eturn system time (in seconds)
+ ///
+ public static double seconds()
+ {
+ return (System.DateTime.Now.Ticks * 1.0E-7);
+ }
+
+ public virtual void reset()
+ {
+ _running = false;
+ _last_time = 0.0;
+ _total = 0.0;
+ }
+
+ public Stopwatch()
+ {
+ reset();
+ }
+
+ ///
+ ///
+ /// Start (and reset) timer
+ ///
+ public virtual void start()
+ {
+ if (!_running)
+ {
+ _running = true;
+ _total = 0.0;
+ _last_time = seconds();
+ }
+ }
+
+ ///
+ ///
+ /// Resume timing, after stopping. (Does not wipe out accumulated times.)
+ ///
+ public virtual void resume()
+ {
+ if (!_running)
+ {
+ _last_time = seconds();
+ _running = true;
+ }
+ }
+
+ ///
+ ///
+ /// Stop timer
+ ///
+ public virtual double stop()
+ {
+ if (_running)
+ {
+ _total += seconds() - _last_time;
+ _running = false;
+ }
+ return _total;
+ }
+
+ ///
+ ///
+ /// return the elapsed time (in seconds)
+ ///
+ public virtual double read()
+ {
+ if (_running)
+ {
+ _total += seconds() - _last_time;
+ _last_time = seconds();
+ }
+ return _total;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/SciMark/kernel.cs b/tests/src/JIT/Performance/CodeQuality/SciMark/kernel.cs
new file mode 100644
index 0000000..5c827f0
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/SciMark/kernel.cs
@@ -0,0 +1,444 @@
+///
+/// This is a port of the SciMark2a Java Benchmark to C# by
+/// Chris Re (cmr28@cornell.edu) and Werner Vogels (vogels@cs.cornell.edu)
+///
+/// For details on the original authors see http://math.nist.gov/scimark2
+///
+/// This software is likely to burn your processor, bitflip your memory chips
+/// anihilate your screen and corrupt all your disks, so you it at your
+/// own risk.
+///
+
+
+using Microsoft.Xunit.Performance;
+using System;
+
+namespace SciMark2
+{
+ public static class kernel
+ {
+ [Benchmark]
+ public static void benchFFT()
+ {
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+ int N = Constants.FFT_SIZE;
+ long Iterations = 20000;
+
+ double[] x = RandomVector(2 * N, R);
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ innerFFT(x, Iterations);
+ }
+ }
+ validateFFT(N, x);
+ }
+
+ private static void innerFFT(double[] x, long Iterations)
+ {
+ for (int i = 0; i < Iterations; i++)
+ {
+ FFT.transform(x); // forward transform
+ FFT.inverse(x); // backward transform
+ }
+ }
+
+ private static void validateFFT(int N, double[] x)
+ {
+ const double EPS = 1.0e-10;
+ if (FFT.test(x) / N > EPS)
+ {
+ throw new Exception("FFT failed to validate");
+ }
+ }
+
+ public static double measureFFT(int N, double mintime, Random R)
+ {
+ // initialize FFT data as complex (N real/img pairs)
+ double[] x = RandomVector(2 * N, R);
+
+ long cycles = 1;
+ Stopwatch Q = new Stopwatch();
+ while (true)
+ {
+ Q.start();
+ innerFFT(x, cycles);
+ Q.stop();
+ if (Q.read() >= mintime)
+ break;
+
+ cycles *= 2;
+ }
+
+ validateFFT(N, x);
+
+ // approx Mflops
+ return FFT.num_flops(N) * cycles / Q.read() * 1.0e-6;
+ }
+
+ [Benchmark]
+ public static void benchSOR()
+ {
+ int N = Constants.SOR_SIZE;
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+ int Iterations = 20000;
+ double[][] G = RandomMatrix(N, N, R);
+
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SOR.execute(1.25, G, Iterations);
+ }
+ }
+ }
+
+ public static double measureSOR(int N, double min_time, Random R)
+ {
+ double[][] G = RandomMatrix(N, N, R);
+ Stopwatch Q = new Stopwatch();
+ int cycles = 1;
+ while (true)
+ {
+ Q.start();
+ SOR.execute(1.25, G, cycles);
+ Q.stop();
+ if (Q.read() >= min_time)
+ break;
+
+ cycles *= 2;
+ }
+
+ // approx Mflops
+ return SOR.num_flops(N, N, cycles) / Q.read() * 1.0e-6;
+ }
+
+ [Benchmark]
+ public static void benchMonteCarlo()
+ {
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+ int Iterations = 40000000;
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ MonteCarlo.integrate(Iterations);
+ }
+ }
+ }
+
+ public static double measureMonteCarlo(double min_time, Random R)
+ {
+ Stopwatch Q = new Stopwatch();
+
+ int cycles = 1;
+ while (true)
+ {
+ Q.start();
+ MonteCarlo.integrate(cycles);
+ Q.stop();
+ if (Q.read() >= min_time)
+ break;
+
+ cycles *= 2;
+ }
+
+ // approx Mflops
+ return MonteCarlo.num_flops(cycles) / Q.read() * 1.0e-6;
+ }
+
+ [Benchmark]
+ public static void benchSparseMult()
+ {
+ int N = Constants.SPARSE_SIZE_M;
+ int nz = Constants.SPARSE_SIZE_nz;
+ int Iterations = 100000;
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+
+ double[] x = RandomVector(N, R);
+ double[] y = new double[N];
+ int nr = nz / N; // average number of nonzeros per row
+ int anz = nr * N; // _actual_ number of nonzeros
+ double[] val = RandomVector(anz, R);
+ int[] col = new int[anz];
+ int[] row = new int[N + 1];
+
+ row[0] = 0;
+ for (int r = 0; r < N; r++)
+ {
+ // initialize elements for row r
+
+ int rowr = row[r];
+ row[r + 1] = rowr + nr;
+ int step = r / nr;
+ if (step < 1)
+ step = 1;
+ // take at least unit steps
+
+ for (int i = 0; i < nr; i++)
+ col[rowr + i] = i * step;
+ }
+
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SparseCompRow.matmult(y, val, row, col, x, Iterations);
+ }
+ }
+ }
+
+ public static double measureSparseMatmult(int N, int nz, double min_time, Random R)
+ {
+ // initialize vector multipliers and storage for result
+ // y = A*y;
+
+ double[] x = RandomVector(N, R);
+ double[] y = new double[N];
+
+ // initialize square sparse matrix
+ //
+ // for this test, we create a sparse matrix wit M/nz nonzeros
+ // per row, with spaced-out evenly between the begining of the
+ // row to the main diagonal. Thus, the resulting pattern looks
+ // like
+ // +-----------------+
+ // +* +
+ // +*** +
+ // +* * * +
+ // +** * * +
+ // +** * * +
+ // +* * * * +
+ // +* * * * +
+ // +* * * * +
+ // +-----------------+
+ //
+ // (as best reproducible with integer artihmetic)
+ // Note that the first nr rows will have elements past
+ // the diagonal.
+
+ int nr = nz / N; // average number of nonzeros per row
+ int anz = nr * N; // _actual_ number of nonzeros
+
+
+ double[] val = RandomVector(anz, R);
+ int[] col = new int[anz];
+ int[] row = new int[N + 1];
+
+ row[0] = 0;
+ for (int r = 0; r < N; r++)
+ {
+ // initialize elements for row r
+
+ int rowr = row[r];
+ row[r + 1] = rowr + nr;
+ int step = r / nr;
+ if (step < 1)
+ step = 1;
+ // take at least unit steps
+
+ for (int i = 0; i < nr; i++)
+ col[rowr + i] = i * step;
+ }
+
+ Stopwatch Q = new Stopwatch();
+
+ int cycles = 1;
+ while (true)
+ {
+ Q.start();
+ SparseCompRow.matmult(y, val, row, col, x, cycles);
+ Q.stop();
+ if (Q.read() >= min_time)
+ break;
+
+ cycles *= 2;
+ }
+
+ // approx Mflops
+ return SparseCompRow.num_flops(N, nz, cycles) / Q.read() * 1.0e-6;
+ }
+
+ [Benchmark]
+ public static void benchmarkLU()
+ {
+ int N = Constants.LU_SIZE;
+ SciMark2.Random R = new SciMark2.Random(Constants.RANDOM_SEED);
+ int Iterations = 2000;
+
+ double[][] A = RandomMatrix(N, N, R);
+ double[][] lu = new double[N][];
+ for (int i = 0; i < N; i++)
+ {
+ lu[i] = new double[N];
+ }
+ int[] pivot = new int[N];
+
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Iterations; i++)
+ {
+ CopyMatrix(lu, A);
+ LU.factor(lu, pivot);
+ }
+ }
+ }
+
+ validateLU(N, R, lu, A, pivot);
+ }
+
+ public static void validateLU(int N, SciMark2.Random R, double[][] lu, double[][] A, int[] pivot)
+ {
+ // verify that LU is correct
+ double[] b = RandomVector(N, R);
+ double[] x = NewVectorCopy(b);
+
+ LU.solve(lu, pivot, x);
+
+ const double EPS = 1.0e-12;
+ if (normabs(b, matvec(A, x)) / N > EPS)
+ {
+ throw new Exception("LU failed to validate");
+ }
+ }
+ public static double measureLU(int N, double min_time, Random R)
+ {
+ // compute approx Mlfops, or O if LU yields large errors
+
+ double[][] A = RandomMatrix(N, N, R);
+ double[][] lu = new double[N][];
+ for (int i = 0; i < N; i++)
+ {
+ lu[i] = new double[N];
+ }
+ int[] pivot = new int[N];
+
+ Stopwatch Q = new Stopwatch();
+
+ int cycles = 1;
+ while (true)
+ {
+ Q.start();
+ for (int i = 0; i < cycles; i++)
+ {
+ CopyMatrix(lu, A);
+ LU.factor(lu, pivot);
+ }
+ Q.stop();
+ if (Q.read() >= min_time)
+ break;
+
+ cycles *= 2;
+ }
+
+ validateLU(N, R, lu, A, pivot);
+
+ return LU.num_flops(N) * cycles / Q.read() * 1.0e-6;
+ }
+
+ private static double[] NewVectorCopy(double[] x)
+ {
+ int N = x.Length;
+
+ double[] y = new double[N];
+ for (int i = 0; i < N; i++)
+ y[i] = x[i];
+
+ return y;
+ }
+
+ private static void CopyVector(double[] B, double[] A)
+ {
+ int N = A.Length;
+
+ for (int i = 0; i < N; i++)
+ B[i] = A[i];
+ }
+
+ private static double normabs(double[] x, double[] y)
+ {
+ int N = x.Length;
+ double sum = 0.0;
+
+ for (int i = 0; i < N; i++)
+ sum += System.Math.Abs(x[i] - y[i]);
+
+ return sum;
+ }
+
+ private static void CopyMatrix(double[][] B, double[][] A)
+ {
+ int M = A.Length;
+ int N = A[0].Length;
+
+ int remainder = N & 3; // N mod 4;
+
+ for (int i = 0; i < M; i++)
+ {
+ double[] Bi = B[i];
+ double[] Ai = A[i];
+ for (int j = 0; j < remainder; j++)
+ Bi[j] = Ai[j];
+ for (int j = remainder; j < N; j += 4)
+ {
+ Bi[j] = Ai[j];
+ Bi[j + 1] = Ai[j + 1];
+ Bi[j + 2] = Ai[j + 2];
+ Bi[j + 3] = Ai[j + 3];
+ }
+ }
+ }
+
+ private static double[][] RandomMatrix(int M, int N, Random R)
+ {
+ double[][] A = new double[M][];
+ for (int i = 0; i < M; i++)
+ {
+ A[i] = new double[N];
+ }
+
+ for (int i = 0; i < N; i++)
+ for (int j = 0; j < N; j++)
+ A[i][j] = R.nextDouble();
+ return A;
+ }
+
+ private static double[] RandomVector(int N, Random R)
+ {
+ double[] A = new double[N];
+
+ for (int i = 0; i < N; i++)
+ A[i] = R.nextDouble();
+ return A;
+ }
+
+ private static double[] matvec(double[][] A, double[] x)
+ {
+ int N = x.Length;
+ double[] y = new double[N];
+
+ matvec(A, x, y);
+
+ return y;
+ }
+
+ private static void matvec(double[][] A, double[] x, double[] y)
+ {
+ int M = A.Length;
+ int N = A[0].Length;
+
+ for (int i = 0; i < M; i++)
+ {
+ double sum = 0.0;
+ double[] Ai = A[i];
+ for (int j = 0; j < N; j++)
+ sum += Ai[j] * x[j];
+
+ y[i] = sum;
+ }
+ }
+ }
+}