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

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


The following commit(s) were added to refs/heads/main by this push:
     new cdc2e2cb26 [SYSTEMDS-3794] Fix multi-threaded sparse matrix-vector 
elementwise ops
cdc2e2cb26 is described below

commit cdc2e2cb26aac10e4729b3e8247911c028011f48
Author: Matthias Boehm <[email protected]>
AuthorDate: Sun Nov 24 13:40:33 2024 +0100

    [SYSTEMDS-3794] Fix multi-threaded sparse matrix-vector elementwise ops
    
    There was a regression where all sparse matrix-vector elementwise
    operations are now only executed single-threaded. This patch fixes
    the most important branch for sparse-safe matrix-vector operations,
    but in subsequent task we also need to fix all the other cases.
    
    When running connected components on the Europe road network, the
    individual binary multiply operations improved by 10-20x on a box with
    48 vcores. End-to-end the entire components() invocation with 20
    iterations improved from 282s (246s for b(*)) to 112s (75s for b(*)).
    The 10x improvements do not carry fully through because the output MCSR
    is converted to CSR when appending to the buffer pool (57s of 75s).
---
 .../runtime/matrix/data/LibMatrixBincell.java      | 48 +++++++++++-----------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git 
a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java 
b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
index d5eb07b244..3eb8d6e2ab 100644
--- a/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
+++ b/src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixBincell.java
@@ -184,7 +184,7 @@ public class LibMatrixBincell {
        public static MatrixBlock bincellOp(MatrixBlock m1, MatrixBlock m2, 
MatrixBlock ret, BinaryOperator op) {
                try{
 
-                       // Timing time = new Timing(true);
+                       //Timing time = new Timing(true);
                        isValidDimensionsBinary(m1, m2);
                        op = replaceOpWithSparseSafeIfApplicable(m1, m2, op);
                        
@@ -212,11 +212,13 @@ public class LibMatrixBincell {
                        int k = op.getNumThreads();
 
                        // fallback to sequential computation for specialized 
operations
+                       // TODO fix all variants to be feasible for 
multi-threading
                        if(k <= 1 || m1.isEmpty() || m2.isEmpty()
                                || ret.getLength() < PAR_NUMCELL_THRESHOLD2
                                || ((op.sparseSafe || 
isSparseSafeDivideOrPow(op, m2))
                                        && !(atype == 
BinaryAccessType.MATRIX_MATRIX
-                                               || atype.isMatrixVector() && 
isAllDense(m1, m2, ret)))
+                                               || (atype.isMatrixVector() && 
isAllDense(m1, m2, ret))
+                                               || (atype.isMatrixVector() && 
m1.sparse && (m2.sparse || ret.sparse))))
                                || !CommonThreadPool.useParallelismOnThread())
                        {
                                bincellOpMatrixSingle(m1, m2, ret, op, atype);
@@ -227,7 +229,7 @@ public class LibMatrixBincell {
                        
                        if(ret.isEmptyBlock(false))
                                ret.examSparsity(k);
-                       // System.out.println("BinCell " + op + " " + 
m1.getNumRows() + ", " + m1.getNumColumns() + ", " + m1.getNonZeros()
+                       //System.out.println("BinCell " + op + " " + 
m1.getNumRows() + ", " + m1.getNumColumns() + ", " + m1.getNonZeros()
                        //      + " -- " + m2.getNumRows() + ", " + 
m2.getNumColumns() + " " + m2.getNonZeros() + "\t\t" + time.stop());
                        
                        return ret;
@@ -732,7 +734,7 @@ public class LibMatrixBincell {
                        && atype == BinaryAccessType.MATRIX_ROW_VECTOR)
                        safeBinaryMVSparseDenseRow(m1, m2, ret, op);
                else if( m1.sparse ) //SPARSE m1
-                       safeBinaryMVSparseLeft(m1, m2, ret, op);
+                       return safeBinaryMVSparseLeft(m1, m2, ret, op, rl, ru);
                else if( !m1.sparse && !m2.sparse && ret.sparse && op.fn 
instanceof Multiply
                        && atype == BinaryAccessType.MATRIX_COL_VECTOR
                        && (long)m1.rlen * m2.clen < Integer.MAX_VALUE )
@@ -977,31 +979,31 @@ public class LibMatrixBincell {
                ret.nonZeros = nnz;
        }
        
-       private static void safeBinaryMVSparseLeft(MatrixBlock m1, MatrixBlock 
m2, MatrixBlock ret, BinaryOperator op) {
+       private static long safeBinaryMVSparseLeft(MatrixBlock m1, MatrixBlock 
m2, MatrixBlock ret, 
+               BinaryOperator op, int rl, int ru)
+       {
                boolean isMultiply = (op.fn instanceof Multiply);
                boolean skipEmpty = (isMultiply || isSparseSafeDivideOrPow(op, 
m2));
                BinaryAccessType atype = getBinaryAccessType(m1, m2);
 
                // early abort on skip and empty
                if(skipEmpty && (m1.isEmptyBlock(false) || 
m2.isEmptyBlock(false)))
-                       return; // skip entire empty block
-
+                       return 0; // skip entire empty block
 
                if(atype == BinaryAccessType.MATRIX_COL_VECTOR)
-                       safeBinaryMVSparseLeftColVector(m1, m2, ret, op);
+                       safeBinaryMVSparseLeftColVector(m1, m2, ret, op, rl, 
ru);
                else if(atype == BinaryAccessType.MATRIX_ROW_VECTOR)
-                       safeBinaryMVSparseLeftRowVector(m1, m2, ret, op);
-
-               ret.recomputeNonZeros();
+                       safeBinaryMVSparseLeftRowVector(m1, m2, ret, op, rl, 
ru);
 
+               return ret.recomputeNonZeros(rl, ru-1);
        }
 
-       @SuppressWarnings("null")
-       private static void safeBinaryMVSparseLeftColVector(MatrixBlock m1, 
MatrixBlock m2, MatrixBlock ret, BinaryOperator op) {
+       private static void safeBinaryMVSparseLeftColVector(MatrixBlock m1, 
MatrixBlock m2, MatrixBlock ret, 
+               BinaryOperator op, int rl, int ru)
+       {
                final boolean isMultiply = (op.fn instanceof Multiply);
                final boolean skipEmpty = (isMultiply || 
isSparseSafeDivideOrPow(op, m2));
 
-               final int rlen = m1.rlen;
                final int clen = m1.clen;
                final SparseBlock a = m1.sparseBlock;
                final boolean aNull = a == null;
@@ -1009,7 +1011,7 @@ public class LibMatrixBincell {
                        return;
                if(ret.isInSparseFormat()){
                        final SparseBlockMCSR rb = (SparseBlockMCSR) 
ret.getSparseBlock();
-                       for(int i = 0; i < rlen; i++) {
+                       for(int i = rl; i < ru; i++) {
                                final double v2 = m2.get(i, 0);
                                final boolean emptyRow = !aNull ? a.isEmpty(i) 
: true;
                                if((skipEmpty && (emptyRow || v2 == 0))  // 
skip empty one side zero
@@ -1029,7 +1031,7 @@ public class LibMatrixBincell {
                }
                else{
                        final DenseBlock db = ret.getDenseBlock();
-                       for(int i = 0; i < rlen; i++) {
+                       for(int i = rl; i < ru; i++) {
                                final double v2 = m2.get(i, 0);
 
                                final boolean emptyRow = !aNull ? a.isEmpty(i) 
: true;
@@ -1045,7 +1047,6 @@ public class LibMatrixBincell {
                                        safeBinaryMVSparseColVectorRowNoFill(a, 
i, db, v2, emptyRow, op);
                                else  // GENERAL CASE
                                        
safeBinaryMVSparseColVectorRowWithFill(a, i, db, vz, v2, clen, emptyRow, op);
-
                        }
                }
        }
@@ -1141,18 +1142,17 @@ public class LibMatrixBincell {
                ret.set(rpos, rpos + 1, cpos, len, v);
        }
 
-       @SuppressWarnings("null")
-       private static void safeBinaryMVSparseLeftRowVector(MatrixBlock m1, 
MatrixBlock m2, MatrixBlock ret, BinaryOperator op) {
+       private static void safeBinaryMVSparseLeftRowVector(MatrixBlock m1, 
MatrixBlock m2, MatrixBlock ret, 
+               BinaryOperator op, int rl, int ru)
+       {
                boolean isMultiply = (op.fn instanceof Multiply);
                boolean skipEmpty = (isMultiply || isSparseSafeDivideOrPow(op, 
m2));
 
-               int rlen = m1.rlen;
                int clen = m1.clen;
                SparseBlock a = m1.sparseBlock;
                if(ret.isInSparseFormat()){
                        SparseBlock sb = ret.getSparseBlock();
-                       long nnz = 0;
-                       for(int i = 0; i < rlen; i++) {
+                       for(int i = rl; i < ru; i++) {
                                if(skipEmpty && (a == null || a.isEmpty(i)))
                                        continue; // skip empty rows
                                if(skipEmpty && ret.sparse)
@@ -1170,18 +1170,16 @@ public class LibMatrixBincell {
                                                double v2 = m2.get(0, aix[j]);
                                                double v = 
op.fn.execute(avals[j], v2);
                                                sb.append(i, aix[j], v);
-                                               nnz += v != 0 ? 1 : 0;
                                                lastIx = aix[j];
                                        }
                                }
                                // empty left
                                fillZeroValues(op, m2, ret, skipEmpty, i, 
lastIx + 1, clen);
                        }
-                       ret.setNonZeros(nnz);
                }
                else{
                        DenseBlock db = ret.getDenseBlock();
-                       for(int i = 0; i < rlen; i++){
+                       for(int i = rl; i < ru; i++){
                                if(skipEmpty && (a == null || a.isEmpty(i)))
                                        continue; // skip empty rows
                                if(skipEmpty && ret.sparse)

Reply via email to