[SYSTEMML-2016] Performance frame cbind and vector frame casts (shallow)

This patch makes major performance improvements to the frame primitives
cbind and matrix (special case of vector) to frame casts, which both can
be done via shallow copies. This is safe due to copy-on-write semantics
of operations. 

On a scenario of 20 iterations of cbind(as.frame(X), cbind(as.frame(Y),
as.frame(Z))) over 10M x 1 dense inputs, this patch improved end-to-end
runtime from 26.1s (15s GC) to 3.9s (0.2s GC). Note that 90% of
remaining execution time is spent in buffer pool evictions, which are
unnecessary and will be addressed in a subsequent patch.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/1e0a4151
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/1e0a4151
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/1e0a4151

Branch: refs/heads/master
Commit: 1e0a4151d21d0821668dd7d0de34ac6b75c33358
Parents: 9e599cd
Author: Matthias Boehm <mboe...@gmail.com>
Authored: Wed Nov 15 22:38:24 2017 -0800
Committer: Matthias Boehm <mboe...@gmail.com>
Committed: Thu Nov 16 00:11:52 2017 -0800

----------------------------------------------------------------------
 .../RewriteAlgebraicSimplificationStatic.java        |  2 +-
 .../apache/sysml/runtime/matrix/data/FrameBlock.java |  8 +++-----
 .../org/apache/sysml/runtime/util/DataConverter.java | 15 +++++++++++----
 3 files changed, 15 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/1e0a4151/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationStatic.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationStatic.java
 
b/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationStatic.java
index d71c4e0..cc2fe88 100644
--- 
a/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationStatic.java
+++ 
b/src/main/java/org/apache/sysml/hops/rewrite/RewriteAlgebraicSimplificationStatic.java
@@ -522,7 +522,7 @@ public class RewriteAlgebraicSimplificationStatic extends 
HopRewriteRule
        private static Hop foldMultipleAppendOperations(Hop hi) 
                throws HopsException
        {
-               if( hi.getDataType().isMatrix() //no string appends
+               if( hi.getDataType().isMatrix() //no string appends or frames
                        && (HopRewriteUtils.isBinary(hi, OpOp2.CBIND, 
OpOp2.RBIND) 
                        || HopRewriteUtils.isNary(hi, OpOpN.CBIND, OpOpN.RBIND))
                        && !OptimizerUtils.isHadoopExecutionMode() )

http://git-wip-us.apache.org/repos/asf/systemml/blob/1e0a4151/src/main/java/org/apache/sysml/runtime/matrix/data/FrameBlock.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/matrix/data/FrameBlock.java 
b/src/main/java/org/apache/sysml/runtime/matrix/data/FrameBlock.java
index a56fd6a..e83b362 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/FrameBlock.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/FrameBlock.java
@@ -471,9 +471,9 @@ public class FrameBlock implements Writable, CacheBlock, 
Externalizable
                for( int j=0; j<ncol; j++ )
                        tmpData[j] = new DoubleArray(cols[j]);
                _colnames = empty ? null : (String[]) 
ArrayUtils.addAll(getColumnNames(), 
-                               createColNames(getNumColumns(), ncol)); 
//before schema modification
+                       createColNames(getNumColumns(), ncol)); //before schema 
modification
                _schema = empty ? tmpSchema : (ValueType[]) 
ArrayUtils.addAll(_schema, tmpSchema); 
-               _coldata = empty ? tmpData : (Array[]) 
ArrayUtils.addAll(_coldata, tmpData);            
+               _coldata = empty ? tmpData : (Array[]) 
ArrayUtils.addAll(_coldata, tmpData);
                _numRows = cols[0].length;
        }
 
@@ -988,10 +988,8 @@ public class FrameBlock implements Writable, CacheBlock, 
Externalizable
                        ret._colnames = (String[]) 
ArrayUtils.addAll(getColumnNames(), that.getColumnNames());
                        ret._colmeta = (ColumnMetadata[]) 
ArrayUtils.addAll(_colmeta, that._colmeta);
                        
-                       //concatenate column data (w/ deep copy to prevent side 
effects)
+                       //concatenate column data (w/ shallow copy which is 
safe due to copy on write semantics)
                        ret._coldata = (Array[]) ArrayUtils.addAll(_coldata, 
that._coldata);
-                       for( int i=0; i<ret.getNumColumns(); i++ )
-                               ret._coldata[i] = ret._coldata[i].clone();
                }
                else //ROW APPEND
                {

http://git-wip-us.apache.org/repos/asf/systemml/blob/1e0a4151/src/main/java/org/apache/sysml/runtime/util/DataConverter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/runtime/util/DataConverter.java 
b/src/main/java/org/apache/sysml/runtime/util/DataConverter.java
index af69e81..bfc07ba 100644
--- a/src/main/java/org/apache/sysml/runtime/util/DataConverter.java
+++ b/src/main/java/org/apache/sysml/runtime/util/DataConverter.java
@@ -654,7 +654,7 @@ public class DataConverter
                
                if( mb.isInSparseFormat() ) //SPARSE
                {
-                       SparseBlock sblock = mb.getSparseBlock();               
        
+                       SparseBlock sblock = mb.getSparseBlock();
                        for( int i=0; i<mb.getNumRows(); i++ ) {
                                Arrays.fill(row, null); //reset
                                if( sblock != null && !sblock.isEmpty(i) ) {
@@ -664,7 +664,7 @@ public class DataConverter
                                        double[] aval = sblock.values(i);
                                        for( int j=apos; j<apos+alen; j++ ) {
                                                row[aix[j]] = 
UtilFunctions.doubleToObject(
-                                                               schema[aix[j]], 
aval[j]);                                       
+                                                               schema[aix[j]], 
aval[j]);
                                        }
                                }
                                frame.appendRow(row);
@@ -673,8 +673,15 @@ public class DataConverter
                else //DENSE
                {
                        int dFreq = UtilFunctions.frequency(schema, 
ValueType.DOUBLE);
-               
-                       if( dFreq == schema.length ) {
+                       
+                       if( schema.length==1 && dFreq==1 && mb.isAllocated() ) {
+                               // special case double schema and single 
columns which
+                               // allows for a shallow copy since the physical 
representation
+                               // of row-major matrix and column-major frame 
match exactly
+                               frame.reset();
+                               frame.appendColumns(new 
double[][]{mb.getDenseBlock()});
+                       }
+                       else if( dFreq == schema.length ) {
                                // special case double schema (without 
cell-object creation, 
                                // col pre-allocation, and cache-friendly 
row-column copy)
                                int m = mb.getNumRows();

Reply via email to