2016-09-27 3 views
1

Я хочу использовать библиотеку Eigen для выполнения вычислений линейной алгебры. В частности, я хочу умножить случайный вектор на случайную матрицу. Вот код, я использую:Умножение векторной матрицы с Eigen

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

using namespace Eigen; 

int main(){ 

    Eigen::initParallel(); 
    Matrix<unsigned int,Dynamic,Dynamic> A; A = Matrix<unsigned int,500,15500>::Random(); 
    Matrix<unsigned int,Dynamic, Dynamic> s; s= Matrix<unsigned int,1,500>::Random(); 
    Matrix<unsigned int,Dynamic,Dynamic> b; 

    auto t1 = std::chrono::high_resolution_clock::now(); 

    b=s*A; 

    auto t2 = std::chrono::high_resolution_clock::now(); 
    auto timeMult = std::chrono::duration_cast <std::chrono::microseconds>(t2 - t1).count(); 
    std::cout << "Result size: " << b.rows() << "x" << b.cols() << std::endl; 
    std::cout << "Time for multiplication: " << timeMult << " microseconds" << std::endl; 

    return 0; 
} 

Затем, чтобы скомпилировать его я

g++ -I. -Wall -std=c++0x -fopenmp main.cpp 

Я считаю, что все работает нормально (я не проверял фактический результат), но это, кажется, очень медленно. Чтобы дать идею, я написал код C++, который делает то же самое, и явно использует thread s, который работает примерно в 54 раза быстрее, чем код, который я вставил выше! В частности, на моей машине это 286904 микросекунды против 5300 микросекунд с моим кодом C++.

Любая идея о том, почему это так медленно и как это сделать быстрее?

EDIT

Я не отправляя код, который я написал, потому что это часть гораздо большего программного обеспечения и делая MWE из него потребует много работы. Вместо этого я собираюсь описать, что он делает: я определил классы для векторов и матриц, которые обертывают std::vector s, затем для выполнения умножения я определяю определенное число thread s, разбивая матрицу на куски и каждый из thread вычисляет линейную комбинацию строк по коэффициентам в векторе. Каждый thread записывает свой частичный результат в другой вектор строки, и, наконец, все векторы суммируются для получения конечного результата. Очень просто. Кстати, я использую 4 thread s, хотя это значение может быть оптимизировано.

+2

Добавьте команду '-O2' или' -O3' в команду компиляции. –

+0

@AviGinsburg Спасибо! Я очень смущен, что забыл об этом ... Во всяком случае с '-O2',' -O3' или даже '-Ofast' время не опускается ниже 21500 микросекунд, что по-прежнему в 4 раза медленнее моего кода! – minomic

+0

Не забудьте отправить код, с которым вы его сравниваете? –

ответ

2

Дополнительно к добавлению -O2 или -O3 к вашим флагам компиляции (как указано в комментариях), вы должны изменить тип s и b к Matrix<unsigned int,1,Dynamic>. Если Eigen знает во время компиляции, что одним из факторов продукта является вектор, он может использовать гораздо более быструю реализацию продукта. На моей машине, которая изменила время выполнения с 25392 мкс до 4751 мкс.

Однако на данный момент вы получите многопоточность для матрично-векторных продуктов (Eigen 3.3rc1).

+0

Отличная идея! Я подтверждаю, что время выполнения составляет около 5300 микросекунд, точно так же, как мой код на C++. – minomic

+1

С Eigen 3.3 не забывайте «-march = native», чтобы получить ускорение AVX. – ggael

Смежные вопросы