Проблема производительности при матрично-матричном умножении с участием MaxRowsAtCompileTime / MaxColsAtCompileTime

В поисках оптимального умножения матрицы на матрицу с использованием eigen3 (и, надеюсь, извлекая выгоду из поддержки SIMD) я написал следующий тест:

#include <iostream>
#include <Eigen/Dense>
#include <ctime>

using namespace Eigen;
using namespace std;

const int test_size= 13;
const int test_size_16b= test_size+1;

typedef Matrix<double, Dynamic, Dynamic, ColMajor, test_size_16b,     test_size_16b> TestMatrix_dyn16b_t;
typedef Matrix<double, Dynamic, Dynamic> TestMatrix_dynalloc_t;
typedef Matrix<double, test_size, test_size> TestMatrix_t;
typedef Matrix<double, test_size_16b, test_size_16b> TestMatrix_fix16b_t;

template<typename TestMatrix_t> EIGEN_DONT_INLINE void test(const char * msg, int m_size= test_size, int n= 10000) {
    double s= 0.0;
    clock_t elapsed= 0;
    TestMatrix_t m3;
    for(int i= 0; i<n; i++) {
        TestMatrix_t m1 = TestMatrix_t::Random(m_size, m_size);
        TestMatrix_t m2= TestMatrix_t::Random(m_size, m_size);

        clock_t begin = clock();
        m3.noalias()= m1*m2;
        clock_t end = clock();
        elapsed+= end - begin;

        // make sure m3 is not optimized away
        s+= m3(1, 1);
    }

    double elapsed_secs = double(elapsed) / CLOCKS_PER_SEC;
    cout << "Elapsed time " << msg << ": " << elapsed_secs << " size " << m3.cols() << ", " << m3.rows() << endl;
}

int main() {
#ifdef  EIGEN_VECTORIZE
    cout << "EIGEN_VECTORIZE on " << endl;
#endif

    test<TestMatrix_t>         ("normal   ");
    test<TestMatrix_dyn16b_t>  ("dyn 16b  ");
    test<TestMatrix_dynalloc_t>("dyn alloc");
    test<TestMatrix_fix16b_t>  ("fix 16b  ", test_size_16b);
}

скомпилировал с помощью g++ -msse3 -O2 -DEIGEN_DONT_PARALLELIZE test.cpp и запустил на Athlon II X2 255. Результат меня несколько удивил:

EIGEN_VECTORIZE on 
Elapsed time normal   : 0.019193 size 13, 13
Elapsed time dyn 16b  : 0.025226 size 13, 13
Elapsed time dyn alloc: 0.018648 size 13, 13
Elapsed time fix 16b  : 0.018221 size 14, 14

Аналогичные результаты достигаются с другими нечетными числами для test_size. Что меня смущает, так это:

  • Прочитав часто задаваемые вопросы по векторизации собственных векторов, я подумал, что матрица 13x13 имеет размер не кратен 16 байтам, поэтому SIMD-оптимизация не принесет пользы. Я ожидал, что время вычислений будет намного хуже, но это не так.
  • Прочитав о необязательных параметрах шаблона, я подумал, что динамические матрицы с фиксированной верхней границей известны во время компиляции будет вести себя так же, как динамически размещаемые матрицы, и поэтому будет иметь аналогичную скорость вычислений. Но это не так. На самом деле это то, что меня больше всего удивляет и что вызвало мой первоначальный поиск: я хотел знать, лучше ли использовать динамическую матрицу с фиксированной верхней границей, которая кратна 16 байтам, чем матрицу фиксированного размера, размер которой не кратен 16 байт.
  • Наконец, интересно, но не так уж удивительно: матрица, фиксированный размер которой кратен 16, не медленнее, чем матрица, длина столбца и строки которой на единицу меньше. SIMD просто делает дополнительный столбец и строку бесплатно.
  • Не мой первоначальный вопрос, но также интересный: когда тест скомпилирован без поддержки SSE2 и, следовательно, без векторизации, относительное время вычислений примерно пропорционально. Матрица фиксированной памяти с динамическим размером снова самая медленная.

Короче говоря, почему Matrix<double, Dynamic, Dynamic, ColMajor, test_size_16b, test_size_16b> намного медленнее? Вы можете подтвердить мои наблюдения и, может быть, даже объяснить их?


person jgeisler    schedule 30.11.2016    source источник


Ответы (1)


FAQ устарел. Начиная с Eigen версии 3.3, невыровненные векторы и матрицы векторизуются.

Затем, что касается того, почему Matrix<double, Dynamic, Dynamic, ColMajor, test_size_16b, test_size_16b> был медленнее, это была просто проблема выбора во время компиляции предпочтительной реализации матричного продукта. Исправление будет частью Eigen 3.3.1.

person ggael    schedule 30.11.2016