0

I want to split an Eigen dynamic-size array by columns evenly over OpenMP threads.

                         thread 0 | thread 1 | thread 2
[[0, 1, 2],                [[0],  |   [[1],  |   [[2],  
 [3, 4, 5],    becomes:     [3],  |    [4],  |    [5],
 [6, 7, 8]]                 [6]]  |    [7]]  |    [8]]

I can use the block method to do that, but I am not sure if Eigen would recognize the subarray for each thread occupies contiguous memory.

When I read the documentation of block type, has an InnerPanel template parameter with the following description:

InnerPanel is true, if the block maps to a set of rows of a row major matrix or to set of columns of a column major matrix (optional). The parameter allows to determine at compile time whether aligned access is possible on the block expression.

Does Eigen know that vectorization over the subarray for each OpenMP thread is possible because each subarray actually occupies contiguous memory?

If not, how to make Eigen know this?

Program:

#include <Eigen/Eigen>
#include <iostream>
int main() {
    // The dimensions of the matrix is not necessary 8 x 8.
    // The dimension is only known at run time.
    Eigen::MatrixXi x(8,8);
    x.fill(0);
    int n_parts = 3;
    #pragma omp parallel for
    for (int i = 0; i < n_parts; ++i) {
        int st = i * x.cols() / n_parts;
        int en = (i + 1) * x.cols() / n_parts;
        x.block(0, st, x.rows(), en - st).fill(i);
    }
    std::cout << x << "\n";
}

Result (g++ test.cpp -I<path to eigen includes> -fopenmp -lgomp):

0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
0 0 1 1 1 2 2 2
1
  • SO must be sleeping. Commented Aug 13, 2017 at 3:52

1 Answer 1

1

To make sure that a block expression is indeed occupying contiguous memory, use middleCols (or leftCols or rightCols) instead:

#include <Eigen/Core>
template<typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
void inspectBlock(const Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel>& block)
{
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

int main() {
    Eigen::MatrixXi x(8,8);
    inspectBlock(x.block(0, 1, x.rows(), 2));
    inspectBlock(x.middleCols(1, 2));
}

Result:

void inspectBlock(const Eigen::Block<ArgType, BlockRows, BlockCols, InnerPanel>&) [with XprType = Eigen::Matrix<int, -1, -1>; int BlockRows = -1; int BlockCols = -1; bool InnerPanel = false]
void inspectBlock(const Eigen::Block<ArgType, BlockRows, BlockCols, InnerPanel>&) [with XprType = Eigen::Matrix<int, -1, -1>; int BlockRows = -1; int BlockCols = -1; bool InnerPanel = true]

Note: -1 is the value of Eigen::Dynamic, i.e., not fixed at compile time.

And of course, if your matrix was row major, you could split int topRows, middleRows or bottomRows, instead.

Sign up to request clarification or add additional context in comments.

3 Comments

Does that also let Eigen know the memory alignment of the subarrays?
Hmm. InnerPanel is true. Let me test what will happen if the array's dimension/boundary of the sub-arrays are not a multiple of the size of simd registers.
I'm not aware that Eigen can be told that sub-blocks are in fact aligned. (I would have thought Ref can be told only to accept aligned blocks, but I did not manage to produce a working example) -- If you really desperately need that, you can make a manual construction using an AlignedMap.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.