You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemds.apache.org by mb...@apache.org on 2021/05/22 19:23:35 UTC

[systemds] branch master updated: [MINOR] Refactoring rand data generation (reduce JIT, nnz maintenance)

This is an automated email from the ASF dual-hosted git repository.

mboehm7 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/systemds.git


The following commit(s) were added to refs/heads/master by this push:
     new 4c5706f  [MINOR] Refactoring rand data generation (reduce JIT, nnz maintenance)
4c5706f is described below

commit 4c5706f2bcc56384894bd0b2adf4bbdca1c7b866
Author: Matthias Boehm <mb...@gmail.com>
AuthorDate: Sat May 22 21:23:04 2021 +0200

    [MINOR] Refactoring rand data generation (reduce JIT, nnz maintenance)
    
    This patch simplifies the rand kernel (single- and multi-threaded) in
    order to reduce JIT compilation overhead (at method granularity) on the
    first kernel call which can be substantial for large matrices.
    Furthermore, we now avoid nnz maintenance per task for fully dense
    matrices. Together, this reduce the execution time for generating 800MB
    FP64 matrices on a box with 112 threads (without allocation) from 45ms
    to ~32ms.
---
 .../runtime/matrix/data/LibMatrixDatagen.java      | 136 ++++++++++++---------
 .../runtime/matrix/data/RandomMatrixGenerator.java |   4 +
 2 files changed, 84 insertions(+), 56 deletions(-)

diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixDatagen.java b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixDatagen.java
index 2f1a51f..586dc5a 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixDatagen.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixDatagen.java
@@ -503,77 +503,96 @@ public class LibMatrixDatagen
 				// are always selected uniformly at random.
 				nnzPRNG.setSeed(seed);
 				
-				boolean localSparse = MatrixBlock.evalSparseFormatInMemory(
+				boolean localSparse = sparsity < 1 && MatrixBlock.evalSparseFormatInMemory(
 					blockrows, blockcols, (long)(sparsity*blockrows*blockcols));
 				if ( localSparse) {
-					
 					SparseBlock c = out.sparseBlock;
 					if(c == null){
 						out.allocateSparseRowsBlock();
 						c = out.sparseBlock;
 					}
-					// Prob [k-1 zeros before a nonzero] = Prob [k-1 < log(uniform)/log(1-p) < k] = p*(1-p)^(k-1), where p=sparsity
-					double log1mp = Math.log(1-sparsity);
-					int idx = 0;  // takes values in range [1, blen*blen] (both ends including)
-					long blocksize = blockrows*blockcols;
-					while(idx < blocksize) {
-						//compute skip to next index
-						idx = idx + (int) Math.ceil(Math.log(nnzPRNG.nextDouble())/log1mp);
-						if ( idx > blocksize) break;
-						// translate idx into (r,c) within the block
-						int rix = (idx-1)/blockcols;
-						int cix = (idx-1)%blockcols;
-						double val = min + (range * valuePRNG.nextDouble());
-						c.allocate(rowoffset+rix, estnnzRow, clen);
-						c.append(rowoffset+rix, coloffset+cix, val);
-					}
+					genSparse(c, clen, blockrows, blockcols, rowoffset, coloffset,
+						sparsity, estnnzRow, min, range, valuePRNG, nnzPRNG);
 				}
 				else {
 					if (sparsity == 1.0) {
-						DenseBlock c = out.getDenseBlock();
-						for(int ii = 0; ii < blockrows; ii++) {
-							double[] cvals = c.values(rowoffset+ii);
-							int cix = c.pos(rowoffset+ii, coloffset);
-							for(int jj = 0; jj < blockcols; jj++)
-								cvals[cix+jj] = min + (range * valuePRNG.nextDouble());
-						}
+						genFullyDense(out.getDenseBlock(), blockrows, blockcols,
+							rowoffset, coloffset, min, range, valuePRNG);
 					}
 					else {
-						if (out.sparse ) {
-							/* This case evaluated only when this function is invoked from CP. 
-							 * In this case:
-							 *     sparse=true -> entire matrix is in sparse format and hence denseBlock=null
-							 *     localSparse=false -> local block is dense, and hence on MR side a denseBlock will be allocated
-							 * i.e., we need to generate data in a dense-style but set values in sparseRows
-							 * 
-							 */
-							// In this case, entire matrix is in sparse format but the current block is dense
-							SparseBlock c = out.sparseBlock;
-							for(int ii=0; ii < blockrows; ii++) {
-								for(int jj=0; jj < blockcols; jj++) {
-									if(nnzPRNG.nextDouble() <= sparsity) {
-										double val = min + (range * valuePRNG.nextDouble());
-										c.allocate(ii+rowoffset, estnnzRow, clen);
-										c.append(ii+rowoffset, jj+coloffset, val);
-									}
-								}
-							}
-						}
-						else {
-							DenseBlock c = out.getDenseBlock();
-							for(int ii = 0; ii < blockrows; ii++) {
-								double[] cvals = c.values(rowoffset+ii);
-								int cix = c.pos(rowoffset+ii, coloffset);
-								for(int jj = 0; jj < blockcols; jj++)
-									if(nnzPRNG.nextDouble() <= sparsity)
-										cvals[cix+jj] =  min + (range * valuePRNG.nextDouble());
-							}
-						}
+						genDense(out, clen, blockrows, blockcols, rowoffset, coloffset,
+							sparsity, estnnzRow, min, range, valuePRNG, nnzPRNG);
 					}
 				} // sparse or dense 
 			} // cbj
 		} // rbi
 	}
+	
+	private static void genSparse(SparseBlock c, int clen, int blockrows, int blockcols, int rowoffset, int coloffset,
+		double sparsity, int estnnzRow, double min, double range, PRNGenerator valuePRNG, UniformPRNGenerator nnzPRNG)
+	{
+		// Prob [k-1 zeros before a nonzero] = Prob [k-1 < log(uniform)/log(1-p) < k] = p*(1-p)^(k-1), where p=sparsity
+		double log1mp = Math.log(1-sparsity);
+		int idx = 0;  // takes values in range [1, blen*blen] (both ends including)
+		long blocksize = blockrows*blockcols;
+		while(idx < blocksize) {
+			//compute skip to next index
+			idx = idx + (int) Math.ceil(Math.log(nnzPRNG.nextDouble())/log1mp);
+			if ( idx > blocksize) break;
+			// translate idx into (r,c) within the block
+			int rix = (idx-1)/blockcols;
+			int cix = (idx-1)%blockcols;
+			double val = min + (range * valuePRNG.nextDouble());
+			c.allocate(rowoffset+rix, estnnzRow, clen);
+			c.append(rowoffset+rix, coloffset+cix, val);
+		}
+	}
+	
+	private static void genDense(MatrixBlock out, int clen, int blockrows, int blockcols, int rowoffset, int coloffset,
+		double sparsity, int estnnzRow, double min, double range, PRNGenerator valuePRNG, UniformPRNGenerator nnzPRNG)
+	{
+		if (out.sparse ) {
+			/* This case evaluated only when this function is invoked from CP. 
+			 * In this case:
+			 *     sparse=true -> entire matrix is in sparse format and hence denseBlock=null
+			 *     localSparse=false -> local block is dense, and hence on MR side a denseBlock will be allocated
+			 * i.e., we need to generate data in a dense-style but set values in sparseRows
+			 * 
+			 */
+			// In this case, entire matrix is in sparse format but the current block is dense
+			SparseBlock c = out.sparseBlock;
+			for(int ii=0; ii < blockrows; ii++) {
+				for(int jj=0; jj < blockcols; jj++) {
+					if(nnzPRNG.nextDouble() <= sparsity) {
+						double val = min + (range * valuePRNG.nextDouble());
+						c.allocate(ii+rowoffset, estnnzRow, clen);
+						c.append(ii+rowoffset, jj+coloffset, val);
+					}
+				}
+			}
+		}
+		else {
+			DenseBlock c = out.getDenseBlock();
+			for(int ii = 0; ii < blockrows; ii++) {
+				double[] cvals = c.values(rowoffset+ii);
+				int cix = c.pos(rowoffset+ii, coloffset);
+				for(int jj = 0; jj < blockcols; jj++)
+					if(nnzPRNG.nextDouble() <= sparsity)
+						cvals[cix+jj] =  min + (range * valuePRNG.nextDouble());
+			}
+		}
+	}
+	
+	private static void genFullyDense(DenseBlock c, int blockrows, int blockcols, int rowoffset, int coloffset, 
+		double min, double range, PRNGenerator valuePRNG)
+	{
+		for(int i = rowoffset; i < rowoffset+blockrows; i++) {
+			double[] cvals = c.values(i);
+			int cix = c.pos(i, coloffset);
+			for(int j = 0; j < blockcols; j++)
+				cvals[cix+j] = min + (range * valuePRNG.nextDouble());
+		}
+	}
 
 	private static void checkMatrixDimensionsAndSparsity(int rows, int cols, double sp) {
 		if( rows < 0 || cols < 0 || sp < 0 || sp > 1)
@@ -618,10 +637,15 @@ public class LibMatrixDatagen
 		public Long call() {
 			//execute rand operations (with block indexes)
 			genRandomNumbers(true, _rl, _ru, _cl, _cu, _out, _rgen, _bSeed, _seeds);
+			
 			//thread-local maintenance of non-zero values
 			int blen =_rgen._blocksize;
-			return _out.recomputeNonZeros(_rl*blen, Math.min(_ru*blen,_rgen._rows)-1,
-				_cl*blen, Math.min(_cu*blen, _rgen._cols)-1);
+			int rl = _rl*blen;
+			int ru = Math.min(_ru*blen,_rgen._rows);
+			int cl = _cl*blen;
+			int cu = Math.min(_cu*blen, _rgen._cols);
+			return _rgen.isFullyDense() ? (long)(ru-rl) * (cu-cl) :
+				_out.recomputeNonZeros(rl, ru-1, cl, cu-1);
 		}
 	}
 }
diff --git a/src/main/java/org/apache/sysds/runtime/matrix/data/RandomMatrixGenerator.java b/src/main/java/org/apache/sysds/runtime/matrix/data/RandomMatrixGenerator.java
index 846cb30..eeddb91 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/RandomMatrixGenerator.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/RandomMatrixGenerator.java
@@ -48,6 +48,10 @@ public class RandomMatrixGenerator {
 		_valuePRNG = null;
 		_mean = 1.0;
 	}
+	
+	public boolean isFullyDense() {
+		return _sparsity == 1 & (_min != 0 | _max != 0);
+	}
 
 	/**
 	 * Instantiates a Random number generator