Repository: systemml
Updated Branches:
  refs/heads/master 08f9e3e47 -> 36c217d38


[MINOR] Performance binary in-place operations, especially plus

This patch makes a minor performance improvement to binary in-place
operations for dense-dense and dense-sparse ops, especially plus. On a
scenario of paramserv ASP, 10 epochs 80 workers, this patch improved the
end-to-end runtime from 212s to 202.


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

Branch: refs/heads/master
Commit: 36c217d38efe8ce031b568a799a9b796a64a1968
Parents: 08f9e3e
Author: Matthias Boehm <[email protected]>
Authored: Thu Jun 21 17:40:36 2018 -0700
Committer: Matthias Boehm <[email protected]>
Committed: Thu Jun 21 17:40:36 2018 -0700

----------------------------------------------------------------------
 .../runtime/matrix/data/LibMatrixBincell.java   | 70 ++++++++++++--------
 1 file changed, 42 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/36c217d3/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixBincell.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixBincell.java 
b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixBincell.java
index 8310e72..48fce40 100644
--- a/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixBincell.java
+++ b/src/main/java/org/apache/sysml/runtime/matrix/data/LibMatrixBincell.java
@@ -1082,10 +1082,12 @@ public class LibMatrixBincell
 
        private static void safeBinaryInPlace(MatrixBlock m1ret, MatrixBlock 
m2, BinaryOperator op) {
                //early abort on skip and empty 
-               if( m1ret.isEmptyBlock(false) && m2.isEmptyBlock(false) )
+               if( (m1ret.isEmpty() && m2.isEmpty() )
+                       || (op.fn instanceof Plus && m2.isEmpty())
+                       || (op.fn instanceof Minus && m2.isEmpty()))
                        return; // skip entire empty block
                //special case: start aggregation
-               else if( op.fn instanceof Plus && m1ret.isEmptyBlock(false) ){
+               else if( op.fn instanceof Plus && m1ret.isEmpty() ){
                        m1ret.copy(m2);
                        return; 
                }
@@ -1094,6 +1096,8 @@ public class LibMatrixBincell
                        safeBinaryInPlaceSparse(m1ret, m2, op);
                else if(!m1ret.sparse && !m2.sparse)
                        safeBinaryInPlaceDense(m1ret, m2, op);
+               else if(m2.sparse && (op.fn instanceof Plus || op.fn instanceof 
Minus))
+                       safeBinaryInPlaceDenseSparseAdd(m1ret, m2, op);
                else //GENERIC
                        safeBinaryInPlaceGeneric(m1ret, m2, op);
        }
@@ -1191,6 +1195,14 @@ public class LibMatrixBincell
                                }
                        }
                }
+               else if( op.fn instanceof Plus ) {
+                       for(int r=0; r<rlen; r++) {
+                               int aix = a.pos(r), bix = b.pos(r);
+                               double[] avals = a.values(r), bvals = 
b.values(r);
+                               LibMatrixMult.vectAdd(bvals, avals, bix, aix, 
clen);
+                               lnnz += UtilFunctions.computeNnz(avals, aix, 
clen);
+                       }
+               }
                else {
                        for(int r=0; r<rlen; r++) {
                                double[] avals = a.values(r), bvals = 
b.values(r);
@@ -1204,36 +1216,38 @@ public class LibMatrixBincell
                m1ret.setNonZeros(lnnz);
        }
        
+       private static void safeBinaryInPlaceDenseSparseAdd(MatrixBlock m1ret, 
MatrixBlock m2, BinaryOperator op) {
+               final int rlen = m1ret.rlen;
+               DenseBlock a = m1ret.denseBlock;
+               SparseBlock b = m2.sparseBlock;
+               long nnz = m1ret.getNonZeros();
+               for(int r=0; r<rlen; r++) {
+                       if( b.isEmpty(r) ) continue;
+                       int apos = a.pos(r), bpos = b.pos(r);
+                       int blen = b.size(r);
+                       int[] bix = b.indexes(r);
+                       double[] avals = a.values(r), bvals = b.values(r);
+                       for(int k = bpos; k<bpos+blen; k++) {
+                               double vold = avals[apos+bix[k]];
+                               double vnew = op.fn.execute(vold, bvals[k]);
+                               nnz += (vold == 0 && vnew != 0) ? 1 :
+                                       (vold != 0 && vnew ==0) ? -1  : 0;
+                               avals[apos+bix[k]] = vnew;
+                       }
+               }
+               m1ret.setNonZeros(nnz);
+       }
+       
        private static void safeBinaryInPlaceGeneric(MatrixBlock m1ret, 
MatrixBlock m2, BinaryOperator op) {
                final int rlen = m1ret.rlen;
                final int clen = m1ret.clen;
-               
-               if( m2.sparse && (op.fn instanceof Plus || op.fn instanceof 
Minus) ) {
-                       if( m2.isEmptyBlock(false) )
-                               return;
-                       SparseBlock b = m2.sparseBlock;
-                       for(int r=0; r<rlen; r++) {
-                               if( b.isEmpty(r) ) continue;
-                               int bpos = b.pos(r);
-                               int blen = b.size(r);
-                               int[] bix = b.indexes(r);
-                               double[] bvals = b.values(r);
-                               for(int k = bpos; k<bpos+blen; k++) {
-                                       double vold = m1ret.quickGetValue(r, 
bix[k]);
-                                       double vnew = op.fn.execute(vold, 
bvals[k]);
-                                       m1ret.quickSetValue(r, bix[k], vnew);
-                               }
+               for(int r=0; r<rlen; r++)
+                       for(int c=0; c<clen; c++) {
+                               double thisvalue = m1ret.quickGetValue(r, c);
+                               double thatvalue = m2.quickGetValue(r, c);
+                               double resultvalue = op.fn.execute(thisvalue, 
thatvalue);
+                               m1ret.quickSetValue(r, c, resultvalue);
                        }
-               }
-               else {
-                       for(int r=0; r<rlen; r++)
-                               for(int c=0; c<clen; c++) {
-                                       double thisvalue = 
m1ret.quickGetValue(r, c);
-                                       double thatvalue = m2.quickGetValue(r, 
c);
-                                       double resultvalue = 
op.fn.execute(thisvalue, thatvalue);
-                                       m1ret.quickSetValue(r, c, resultvalue);
-                               }
-               }
        }
        
        private static void unsafeBinaryInPlace(MatrixBlock m1ret, MatrixBlock 
m2, BinaryOperator op)

Reply via email to