Подтвердить что ты не робот

Сравнить blitz ++, armadillo, boost:: 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

В Windows, Intel С++, результаты

[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 С++, файл bzconfig.h требуется в blitz/intel/folder. Но нет. Я просто копирую один в blitz/ms/bzconfig.h. Это может дать неоптимальную конфигурацию. Кто-нибудь может сказать мне, как скомпилировать blitz ++ с компилятором intel С++? В руководстве сказано, что запустить bzconfig script, чтобы получить правильный 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++ behavior in intel c++ compiler with proper configuration.
   Please see my question.
4b9b3361

Ответ 1

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

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

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

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

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

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

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

Если "неоптимальный" означает "нерабочий" для вас, то да.:-) Вам нужен intel/bzconfig.h, который точно представляет ваш компилятор.

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

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

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

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

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

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

PS: Ищем "bzconfig" в содержании blitz-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 больше не включен.

Ответ 2

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

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

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

Обсуждается уровень BLAS 1 по сравнению с кодом, выпущенным компилятором здесь.

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

Ответ 3

Мой тест показал, что массивы повышения производительности имеют ту же производительность, что и код на С++ на основе /hardcoded.

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