From 0ea0848047b6576ac6ae885a91991740416202d1 Mon Sep 17 00:00:00 2001
From: Henry Weller <http://cfd.direct>
Date: Sun, 20 Mar 2016 15:00:36 +0000
Subject: [PATCH] Matrix: Replace the row-start pointer array with computed
 offsets

The row-start pointer array provided performance benefits on old
computers but now that computation is often cache-miss limited the
benefit of avoiding a integer multiply is more than offset by the
addition memory access into a separately allocated array.

With the new addressing scheme LUsolve is 15% faster.
---
 src/OpenFOAM/matrices/Matrix/Matrix.C         | 91 ++++++++-----------
 src/OpenFOAM/matrices/Matrix/Matrix.H         | 30 ++++--
 src/OpenFOAM/matrices/Matrix/MatrixI.H        | 55 +++++++++--
 src/OpenFOAM/matrices/Matrix/MatrixIO.C       |  8 +-
 .../scalarMatrices/scalarMatricesTemplates.C  |  2 -
 .../primitives/MatrixSpace/MatrixSpace.H      |  6 +-
 .../primitives/MatrixSpace/MatrixSpaceI.H     | 16 ++--
 7 files changed, 120 insertions(+), 88 deletions(-)

diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.C b/src/OpenFOAM/matrices/Matrix/Matrix.C
index ec9ae8b1b0f..829156693ca 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.C
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.C
@@ -32,13 +32,7 @@ void Foam::Matrix<Form, Type>::allocate()
 {
     if (nRows_ && nCols_)
     {
-        v_ = new Type*[nRows_];
-        v_[0] = new Type[nRows_*nCols_];
-
-        for (label i=1; i<nRows_; i++)
-        {
-            v_[i] = v_[i-1] + nCols_;
-        }
+        v_ = new Type[size()];
     }
 }
 
@@ -50,7 +44,6 @@ Foam::Matrix<Form, Type>::~Matrix()
 {
     if (v_)
     {
-        delete[] (v_[0]);
         delete[] v_;
     }
 }
@@ -59,16 +52,16 @@ Foam::Matrix<Form, Type>::~Matrix()
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::Matrix(const label n, const label m)
+Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
 :
-    nRows_(n),
-    nCols_(m),
+    nRows_(m),
+    nCols_(n),
     v_(NULL)
 {
     if (nRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "bad n, m " << nRows_ << ", " << nCols_
+            << "Bad m, n " << nRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -77,16 +70,16 @@ Foam::Matrix<Form, Type>::Matrix(const label n, const label m)
 
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::Matrix(const label n, const label m, const Type& a)
+Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& a)
 :
-    nRows_(n),
-    nCols_(m),
+    nRows_(m),
+    nCols_(n),
     v_(NULL)
 {
     if (nRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "bad n, m " << nRows_ << ", " << nCols_
+            << "bad m, n " << nRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -94,13 +87,10 @@ Foam::Matrix<Form, Type>::Matrix(const label n, const label m, const Type& a)
 
     if (v_)
     {
-        Type* v = v_[0];
-
-        label mn = nRows_*nCols_;
-
+        const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v[i] = a;
+            v_[i] = a;
         }
     }
 }
@@ -116,13 +106,11 @@ Foam::Matrix<Form, Type>::Matrix(const Matrix<Form, Type>& a)
     if (a.v_)
     {
         allocate();
-        Type* v = v_[0];
-        const Type* av = a.v_[0];
 
-        label mn = nRows_*nCols_;
+        const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v[i] = av[i];
+            v_[i] = a.v_[i];
         }
     }
 }
@@ -133,12 +121,12 @@ void Foam::Matrix<Form, Type>::clear()
 {
     if (v_)
     {
-        delete[] (v_[0]);
         delete[] v_;
+        v_ = NULL;
     }
+
     nRows_ = 0;
     nCols_ = 0;
-    v_ = NULL;
 }
 
 
@@ -183,12 +171,10 @@ void Foam::Matrix<Form, Type>::operator=(const Type& t)
 {
     if (v_)
     {
-        Type* v = v_[0];
-
-        label mn = nRows_*nCols_;
+        const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v[i] = t;
+            v_[i] = t;
         }
     }
 }
@@ -214,13 +200,10 @@ void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
 
     if (v_)
     {
-        Type* v = v_[0];
-        const Type* av = a.v_[0];
-
-        label mn = nRows_*nCols_;
+        const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v[i] = av[i];
+            v_[i] = a.v_[i];
         }
     }
 }
@@ -231,12 +214,12 @@ void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
 template<class Form, class Type>
 const Type& Foam::max(const Matrix<Form, Type>& a)
 {
-    label mn = a.m()*a.n();
+    const label mn = a.size();
 
     if (mn)
     {
         label curMaxI = 0;
-        const Type* v = a[0];
+        const Type* v = a.v();
 
         for (label i=1; i<mn; i++)
         {
@@ -263,12 +246,12 @@ const Type& Foam::max(const Matrix<Form, Type>& a)
 template<class Form, class Type>
 const Type& Foam::min(const Matrix<Form, Type>& a)
 {
-    label mn = a.m()*a.n();
+    const label mn = a.size();
 
     if (mn)
     {
         label curMinI = 0;
-        const Type* v = a[0];
+        const Type* v = a.v();
 
         for (label i=1; i<mn; i++)
         {
@@ -301,10 +284,10 @@ Form Foam::operator-(const Matrix<Form, Type>& a)
 
     if (a.m() && a.n())
     {
-        Type* nav = na[0];
-        const Type* av = a[0];
+        Type* nav = na.v();
+        const Type* av = a.v();
 
-        label mn = a.m()*a.n();
+        const label mn = a.size();
         for (label i=0; i<mn; i++)
         {
             nav[i] = -av[i];
@@ -336,11 +319,11 @@ Form Foam::operator+(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
 
     Form ab(a.m(), a.n());
 
-    Type* abv = ab[0];
-    const Type* av = a[0];
-    const Type* bv = b[0];
+    Type* abv = ab.v();
+    const Type* av = a.v();
+    const Type* bv = b.v();
 
-    label mn = a.m()*a.n();
+    const label mn = a.size();
     for (label i=0; i<mn; i++)
     {
         abv[i] = av[i] + bv[i];
@@ -371,11 +354,11 @@ Form Foam::operator-(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
 
     Form ab(a.m(), a.n());
 
-    Type* abv = ab[0];
-    const Type* av = a[0];
-    const Type* bv = b[0];
+    Type* abv = ab.v();
+    const Type* av = a.v();
+    const Type* bv = b.v();
 
-    label mn = a.m()*a.n();
+    const label mn = a.size();
     for (label i=0; i<mn; i++)
     {
         abv[i] = av[i] - bv[i];
@@ -392,10 +375,10 @@ Form Foam::operator*(const scalar s, const Matrix<Form, Type>& a)
 
     if (a.m() && a.n())
     {
-        Type* sav = sa[0];
-        const Type* av = a[0];
+        Type* sav = sa.v();
+        const Type* av = a.v();
 
-        label mn = a.m()*a.n();
+        const label mn = a.size();
         for (label i=0; i<mn; i++)
         {
             sav[i] = s*av[i];
diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.H b/src/OpenFOAM/matrices/Matrix/Matrix.H
index 49bf41fc6fc..043b9561aa7 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.H
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.H
@@ -79,10 +79,9 @@ class Matrix
         label nRows_, nCols_;
 
         //- Row pointers
-        Type** __restrict__ v_;
+        Type* __restrict__ v_;
 
-        //- Allocate the storage for the row-pointers and the data
-        //  and set the row pointers
+        //- Allocate the storage for the element vector
         void allocate();
 
 
@@ -100,11 +99,11 @@ public:
         inline Matrix();
 
         //- Construct given number of rows and columns.
-        Matrix(const label n, const label m);
+        Matrix(const label m, const label n);
 
         //- Construct with given number of rows and columns
         //  and value for all elements.
-        Matrix(const label n, const label m, const Type&);
+        Matrix(const label m, const label n, const Type&);
 
         //- Copy constructor.
         Matrix(const Matrix<Form, Type>&);
@@ -130,16 +129,16 @@ public:
             //- Return the number of columns
             inline label n() const;
 
-            //- Return the number of elements in matrix (n*m)
+            //- Return the number of elements in matrix (m*n)
             inline label size() const;
 
 
         // Check
 
-            //- Check index i is within valid range (0 ... n-1).
+            //- Check index i is within valid range (0 ... m-1).
             inline void checki(const label i) const;
 
-            //- Check index j is within valid range (0 ... m-1).
+            //- Check index j is within valid range (0 ... n-1).
             inline void checkj(const label j) const;
 
 
@@ -159,12 +158,24 @@ public:
 
     // Member operators
 
+        //- Return element vector of the constant Matrix
+        inline const Type* v() const;
+
+        //- Return element vector of the Matrix
+        inline Type* v();
+
         //- Return subscript-checked row of Matrix.
         inline Type* operator[](const label);
 
         //- Return subscript-checked row of constant Matrix.
         inline const Type* operator[](const label) const;
 
+        //- (i, j) const element access operator
+        inline const Type& operator()(const label i, const label j) const;
+
+        //- (i, j) element access operator
+        inline Type& operator()(const label i, const label j);
+
         //- Assignment operator. Takes linear time.
         void operator=(const Matrix<Form, Type>&);
 
@@ -221,13 +232,14 @@ template<class Form, class Type> Form operator*
     const Matrix<Form, Type>&
 );
 
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-    #include "MatrixI.H"
+#include "MatrixI.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixI.H b/src/OpenFOAM/matrices/Matrix/MatrixI.H
index fbfd4462819..b9ecb4c744b 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixI.H
+++ b/src/OpenFOAM/matrices/Matrix/MatrixI.H
@@ -51,7 +51,6 @@ inline const Foam::Matrix<Form, Type>& Foam::Matrix<Form, Type>::null()
 }
 
 
-//- Return the number of rows
 template<class Form, class Type>
 inline Foam::label Foam::Matrix<Form, Type>::m() const
 {
@@ -76,6 +75,7 @@ inline Foam::label Foam::Matrix<Form, Type>::size() const
 template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checki(const label i) const
 {
+    #ifdef FULLDEBUG
     if (!nRows_)
     {
         FatalErrorInFunction
@@ -88,12 +88,14 @@ inline void Foam::Matrix<Form, Type>::checki(const label i) const
             << "index " << i << " out of range 0 ... " << nRows_-1
             << abort(FatalError);
     }
+    #endif
 }
 
 
 template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checkj(const label j) const
 {
+    #ifdef FULLDEBUG
     if (!nCols_)
     {
         FatalErrorInFunction
@@ -106,28 +108,65 @@ inline void Foam::Matrix<Form, Type>::checkj(const label j) const
             << "index " << j << " out of range 0 ... " << nCols_-1
             << abort(FatalError);
     }
+    #endif
 }
 
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-inline Type* Foam::Matrix<Form, Type>::operator[](const label i)
+inline const Type* Foam::Matrix<Form, Type>::v() const
+{
+    return v_;
+}
+
+
+template<class Form, class Type>
+inline Type* Foam::Matrix<Form, Type>::v()
+{
+    return v_;
+}
+
+
+template<class Form, class Type>
+inline const Type& Foam::Matrix<Form, Type>::operator()
+(
+    const label i,
+    const label j
+) const
 {
-    #ifdef FULLDEBUG
     checki(i);
-    #endif
-    return v_[i];
+    checki(j);
+    return v_[i*nCols_ + j];
+}
+
+
+template<class Form, class Type>
+inline Type& Foam::Matrix<Form, Type>::operator()
+(
+    const label i,
+    const label j
+)
+{
+    checki(i);
+    checki(j);
+    return v_[i*nCols_ + j];
 }
 
 
 template<class Form, class Type>
 inline const Type* Foam::Matrix<Form, Type>::operator[](const label i) const
 {
-    #ifdef FULLDEBUG
     checki(i);
-    #endif
-    return v_[i];
+    return v_ + i*nCols_;
+}
+
+
+template<class Form, class Type>
+inline Type* Foam::Matrix<Form, Type>::operator[](const label i)
+{
+    checki(i);
+    return v_ + i*nCols_;
 }
 
 
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixIO.C b/src/OpenFOAM/matrices/Matrix/MatrixIO.C
index edf2c54b22d..9be178c12f3 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixIO.C
+++ b/src/OpenFOAM/matrices/Matrix/MatrixIO.C
@@ -73,7 +73,7 @@ Foam::Istream& Foam::operator>>(Istream& is, Matrix<Form, Type>& M)
             if (mn)
             {
                 M.allocate();
-                Type* v = M.v_[0];
+                Type* v = M.v_;
 
                 if (listDelimiter == token::BEGIN_LIST)
                 {
@@ -124,7 +124,7 @@ Foam::Istream& Foam::operator>>(Istream& is, Matrix<Form, Type>& M)
             if (mn)
             {
                 M.allocate();
-                Type* v = M.v_[0];
+                Type* v = M.v_;
 
                 is.read(reinterpret_cast<char*>(v), mn*sizeof(Type));
 
@@ -162,7 +162,7 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const Matrix<Form, Type>& M)
         {
             bool uniform = false;
 
-            const Type* v = M.v_[0];
+            const Type* v = M.v_;
 
             if (mn > 1 && contiguous<Type>())
             {
@@ -248,7 +248,7 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const Matrix<Form, Type>& M)
     {
         if (mn)
         {
-            os.write(reinterpret_cast<const char*>(M.v_[0]), mn*sizeof(Type));
+            os.write(reinterpret_cast<const char*>(M.v_), mn*sizeof(Type));
         }
     }
 
diff --git a/src/OpenFOAM/matrices/scalarMatrices/scalarMatricesTemplates.C b/src/OpenFOAM/matrices/scalarMatrices/scalarMatricesTemplates.C
index 59ca2d34e5c..077fa60ced7 100644
--- a/src/OpenFOAM/matrices/scalarMatrices/scalarMatricesTemplates.C
+++ b/src/OpenFOAM/matrices/scalarMatrices/scalarMatricesTemplates.C
@@ -56,8 +56,6 @@ void Foam::solve
 
         if (i != iMax)
         {
-            //Info<< "Pivoted on " << i << " " << iMax << endl;
-
             for (label k=i; k<m; k++)
             {
                 Swap(tmpMatrix[i][k], tmpMatrix[iMax][k]);
diff --git a/src/OpenFOAM/primitives/MatrixSpace/MatrixSpace.H b/src/OpenFOAM/primitives/MatrixSpace/MatrixSpace.H
index 7d1b1186f4b..fd0beaca09d 100644
--- a/src/OpenFOAM/primitives/MatrixSpace/MatrixSpace.H
+++ b/src/OpenFOAM/primitives/MatrixSpace/MatrixSpace.H
@@ -279,12 +279,12 @@ public:
         //- (i, j) const element access operator
         inline const Cmpt& operator()
         (
-            const direction& row,
-            const direction& col
+            const direction& i,
+            const direction& j
         ) const;
 
         //- (i, j) element access operator
-        inline Cmpt& operator()(const direction& row, const direction& col);
+        inline Cmpt& operator()(const direction& i, const direction& j);
 
 
     // Member Operators
diff --git a/src/OpenFOAM/primitives/MatrixSpace/MatrixSpaceI.H b/src/OpenFOAM/primitives/MatrixSpace/MatrixSpaceI.H
index a7afa55fdfc..3fca897851c 100644
--- a/src/OpenFOAM/primitives/MatrixSpace/MatrixSpaceI.H
+++ b/src/OpenFOAM/primitives/MatrixSpace/MatrixSpaceI.H
@@ -322,12 +322,12 @@ Foam::MatrixSpace<Form, Cmpt, Nrows, Ncols>::block()
 template<class Form, class Cmpt, Foam::direction Nrows, Foam::direction Ncols>
 inline const Cmpt& Foam::MatrixSpace<Form, Cmpt, Nrows, Ncols>::operator()
 (
-    const direction& row,
-    const direction& col
+    const direction& i,
+    const direction& j
 ) const
 {
     #ifdef FULLDEBUG
-    if (row < 0 || row > Nrows-1 || col < 0 || col > Ncols-1)
+    if (i < 0 || i > Nrows-1 || j < 0 || j > Ncols-1)
     {
         FatalErrorInFunction
             << "indices out of range"
@@ -335,19 +335,19 @@ inline const Cmpt& Foam::MatrixSpace<Form, Cmpt, Nrows, Ncols>::operator()
     }
     #endif
 
-    return this->v_[row*Ncols + col];
+    return this->v_[i*Ncols + j];
 }
 
 
 template<class Form, class Cmpt, Foam::direction Nrows, Foam::direction Ncols>
 inline Cmpt& Foam::MatrixSpace<Form, Cmpt, Nrows, Ncols>::operator()
 (
-    const direction& row,
-    const direction& col
+    const direction& i,
+    const direction& j
 )
 {
     #ifdef FULLDEBUG
-    if (row < 0 || row > Nrows-1 || col < 0 || col > Ncols-1)
+    if (i < 0 || i > Nrows-1 || j < 0 || j > Ncols-1)
     {
         FatalErrorInFunction
             << "indices out of range"
@@ -355,7 +355,7 @@ inline Cmpt& Foam::MatrixSpace<Form, Cmpt, Nrows, Ncols>::operator()
     }
     #endif
 
-    return this->v_[row*Ncols + col];
+    return this->v_[i*Ncols + j];
 }
 
 
-- 
GitLab