Сравните блиц ++, броненосец, буст :: MultiArray

Я сделал сравнение между blitz ++, armadillo, boost :: MultiArray с помощью следующего кода (заимствовано из старый пост)

#include <iostream>
using namespace std;
#include <windows.h>
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_DISABLE_ASSERTS
#include <boost/multi_array.hpp>
#include <blitz/array.h>
#include <armadillo>

int main(int argc, char* argv[])
{
const int X_SIZE = 1000;
const int Y_SIZE = 1000;
const int ITERATIONS = 100;
unsigned int startTime = 0;
unsigned int endTime = 0;

// Create the boost array//------------------Measure boost Loop------------------------------------------
{
typedef boost::multi_array<double, 2> ImageArrayType;
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
boostMatrix[x][y] = 1.0001;
}
}
}
endTime = ::GetTickCount();
printf("[Boost Loop] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}
//------------------Measure blitz Loop-------------------------------------------
{
blitz::Array<double, 2> blitzArray( X_SIZE, Y_SIZE );
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
blitzArray(x,y) = 1.0001;
}
}
}
endTime = ::GetTickCount();
printf("[Blitz Loop] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}

//------------------Measure armadillo loop----------------------------------------
{
arma::mat matArray( X_SIZE, Y_SIZE );
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int y = 0; y < Y_SIZE; ++y)
{
for (int x = 0; x < X_SIZE; ++x)
{
matArray(x,y) = 1.0001;
}
}
}
endTime = ::GetTickCount();
printf("[arma  Loop]  Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}

//------------------Measure native loop----------------------------------------
// Create the native array
{
double *nativeMatrix = new double [X_SIZE * Y_SIZE];
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int y = 0; y < Y_SIZE*X_SIZE; ++y)
{
nativeMatrix[y] = 1.0001;
}
}
endTime = ::GetTickCount();
printf("[Native Loop]Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
delete[] nativeMatrix;
}

//------------------Measure boost computation-----------------------------------
{
typedef boost::multi_array<double, 2> ImageArrayType;
ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
boostMatrix[x][y] = 1.0001;
}
}
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int x = 0; x < X_SIZE; ++x)
{
for (int y = 0; y < Y_SIZE; ++y)
{
boostMatrix[x][y] += boostMatrix[x][y] * 0.5;
}
}
}
endTime = ::GetTickCount();
printf("[Boost computation] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}

//------------------Measure blitz computation-----------------------------------
{
blitz::Array<double, 2> blitzArray( X_SIZE, Y_SIZE );
blitzArray = 1.0001;
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
blitzArray += blitzArray*0.5;
}
endTime = ::GetTickCount();
printf("[Blitz computation] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}

//------------------Measure armadillo computation-------------------------------
{
arma::mat matArray( X_SIZE, Y_SIZE );
matArray.fill(1.0001);
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
//matArray.fill(1.0001);
matArray += matArray*0.5;
}
endTime = ::GetTickCount();
printf("[arma  computation] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
}

//------------------Measure native computation------------------------------------------
// Create the native array
{
double *nativeMatrix = new double [X_SIZE * Y_SIZE];
for (int y = 0; y < Y_SIZE*X_SIZE; ++y)
{
nativeMatrix[y] = 1.0001;
}
startTime = ::GetTickCount();
for (int i = 0; i < ITERATIONS; ++i)
{
for (int y = 0; y < Y_SIZE*X_SIZE; ++y)
{
nativeMatrix[y] += nativeMatrix[y] * 0.5;
}
}
endTime = ::GetTickCount();
printf("[Native computation]Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);
delete[] nativeMatrix;
}

return 0;
}

На окнах VS2010 результаты

[Boost Loop] Elapsed time:  1.217 seconds
[Blitz Loop] Elapsed time:  0.046 seconds
[arma  Loop]  Elapsed time:  0.078 seconds
[Native Loop]Elapsed time:  0.172 seconds
[Boost computation] Elapsed time:  2.152 seconds
[Blitz computation] Elapsed time:  0.156 seconds
[arma  computation] Elapsed time:  0.078 seconds
[Native computation]Elapsed time:  0.078 seconds

На окнах Intel C ++ результаты

[Boost Loop] Elapsed time:  0.468 seconds
[Blitz Loop] Elapsed time:  0.125 seconds
[arma  Loop]  Elapsed time:  0.046 seconds
[Native Loop]Elapsed time:  0.047 seconds
[Boost computation] Elapsed time:  0.796 seconds
[Blitz computation] Elapsed time:  0.109 seconds
[arma  computation] Elapsed time:  0.078 seconds
[Native computation]Elapsed time:  0.062 seconds

Что-то странное:

(1) with VS2010, native computation (including loop) is faster than native loop
(2) blitz loop behave so different under VS2010 and intel C++.

Чтобы скомпилировать blitz ++ с помощью компилятора intel c ++, в папке blitz / intel / требуется файл bzconfig.h. Но нет. Я просто копирую один в blitz / ms / bzconfig.h в. Это может дать неоптимальную конфигурацию. Кто-нибудь может сказать мне, как скомпилировать блиц ++ с компилятором Intel C ++? В руководстве говорится, что запустите скрипт bzconfig, чтобы получить правильный файл bzconfig.h. Но я не понимаю, что это значит.

Большое спасибо!

Добавьте некоторые из моих выводов:

1. Boost multi array is the slowest.
2. With intel c++ compiler, native pointers are very fast.
3. With intel c++ compiler,  armadillo can achieve the performance of native pointers.
4. Also test eigen, it is x0% slower than armadillo in my simple cases.
5. Curious about blitz++'s behavior in intel c++ compiler with proper configuration.
Please see my question.

33

Решение

Короткий ответ: ./configure CXX=icpc, найденный, прочитав Руководство пользователя Blitz ++.

Длинный ответ:

Чтобы скомпилировать blitz ++ с помощью компилятора intel c ++, в папке blitz / intel / требуется файл bzconfig.h. Но нет.

Да и да. Blitz ++ должен генерировать сам файл. Согласно Руководству пользователя Blitz ++ blitz.pdf включен в blitz-0.10.tar.gz, раздел «Установка»,

Blitz ++ использует GNU Autoconf, который обрабатывает перезапись Make-файлов для различных платформ и компиляторов.

Точнее, Blitz ++ использует цепочку инструментов GNU autotools (automake, autoconf, configure), которая может генерировать make-файлы, настраивать сценарии, заголовочные файлы и многое другое. bzconfig.h файлы должны быть сгенерированы configure Скрипт, который поставляется с Blitz ++, готов к использованию.

Я просто копирую один в blitz / ms / bzconfig.h в. Это может дать неоптимальную конфигурацию.

Если «неоптимальный» для вас означает «неработающий», тогда да. 🙂
Вам нужен intel/bzconfig.h это точно представляет ваш компилятор.

Кто-нибудь может сказать мне, как скомпилировать блиц ++ с компилятором Intel C ++?

Прочитайте и следуйте инструкциям, в частности, разделу «Установка», упомянутому выше.

перейдите в каталог «blitz-VERSION» и введите:
./configure CXX=[compiler]
где [компилятор] является одним из xlc ++, icpc, pathCC, xlC, cxx, aCC, CC, g ++, KCC, pgCC или FCC.
(Если вы не выберете компилятор C ++, скрипт configure попытается найти подходящий компилятор для текущей платформы.)

Вы сделали это? Для компилятора Intel вам нужно будет использовать
./configure CXX=icpc,

В руководстве говорится, что запустите скрипт bzconfig, чтобы получить правильный файл bzconfig.h. Но я не понимаю, что это значит.

Я предполагаю, что под «этим» вы подразумеваете «это». Что вы подразумеваете под «руководством»? Моя копия Руководства пользователя Blitz ++ не упоминает bzconfig, Вы уверены, что используете руководство, соответствующее вашей версии Blitz ++?

PS: ищу «bzconfig» в содержании блиц-0,10, похоже, что «bzconfig» больше не является частью Blitz ++, но раньше был:

find . -name bzconfig -> Нет результатов

find . -print0 | xargs -0 grep -a -i -n -e bzconfig:

./blitz/compiler.h:44:    #error  In <blitz/config.h>: A working template implementation is required by Blitz++ (you may need to rerun the compiler/bzconfig script)

Это должно быть обновлено.

./blitz/gnu/bzconfig.h:4:/* blitz/gnu/bzconfig.h. Generated automatically at end of configure. */
./configure.ac:159:# autoconf replacement of bzconfig

Вот оно, эти bzconfig.h файлы должны быть сгенерированы configure,

./ChangeLog.1:1787: will now replace the old file that was generate with the bzconfig

Это может быть изменение, которое переключилось на autoconf.

./INSTALL:107:  2. Go into the compiler subdirectory and run the bzconfig

Это должно быть обновлено. Это то, что заставило тебя искать bzconfig?

./README:27:compiler      Compiler tests (used with obsolete bzconfig script)

Нуждается в обновлении compiler Каталог больше не включен.

3

Другие решения

Насколько я могу судить, вы оцениваете производительность каждой библиотеки матриц, измеряя скорость умножения одной матрицы на скаляр. Благодаря своей политике на основе шаблонов, Armadillo сделает очень хорошую работу, разбив каждое умножение на распараллеливаемый код для большинства компиляторов.

Но я предлагаю вам переосмыслить объем и методику тестирования. Например, вы оставили каждый BLAS реализация. Функция BLAS, которая вам нужна dscal. Предоставленная поставщиком реализация для вашего конкретного ЦП, вероятно, сработает хорошо.

Более уместно, есть еще много вещей, которые любая разумная библиотека векторов должна уметь делать: умножение матриц, точечные произведения, длины векторов, транспонирование и т. Д., Которые не учитываются вашим тестом. В вашем тесте рассматриваются ровно две вещи: назначение элементов, которое практически не является узким местом для векторных библиотек, и скалярное / векторное умножение, которое является функцией уровня 1 BLAS, предоставляемой каждым производителем ЦП.

Существует обсуждение уровня 1 BLAS против кода, сгенерированного компилятором. Вот.

ТЛ: д-р; используйте Armadillo с собственными библиотеками BLAS и LAPACK для вашей платформы.

3

Мой тест показал, что буст-массивы имеют ту же производительность, что и нативный / жестко закодированный код C ++.

Вам нужно сравнить их, используя активированную оптимизацию компилятора. То есть:
-O3
-DNDEBUG
-DBOOST_UBLAS_NDEBUG
-DBOOST_DISABLE_ASSERTS
-DARMA_NO_DEBUG

Когда я тестировал (em ++), Boost работал как минимум в 10 раз быстрее, когда вы деактивировали его утверждения, включите оптимизацию 3 уровня, используя -O3и т. д. Любое справедливое сравнение должно использовать эти флаги.

1
По вопросам рекламы [email protected]