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

Boost:: multi_array вопрос производительности

Я пытаюсь сравнить производительность boost:: multi_array с родными динамически распределенными массивами со следующей тестовой программой:

#include <windows.h>
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_DISABLE_ASSERTS 
#include <boost/multi_array.hpp>

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

    // Create the boost array
    typedef boost::multi_array<double, 2> ImageArrayType;
    ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);

    // Create the native array
    double *nativeMatrix = new double [X_SIZE * Y_SIZE];

    //------------------Measure boost----------------------------------------------
    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)
            {
                boostMatrix[x][y] = 2.345;
            }
        }
    }
    endTime = ::GetTickCount();
    printf("[Boost] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);

    //------------------Measure native-----------------------------------------------
    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)
            {
                nativeMatrix[x + (y * X_SIZE)] = 2.345;
            }
        }
    }
    endTime = ::GetTickCount();
    printf("[Native]Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);

    return 0;
}

Получаю следующие результаты:

[Boost] Elapsed time: 12.500 seconds
[Native]Elapsed time:  0.062 seconds

Я не могу поверить, что multi_arrays намного медленнее. Может ли кто-нибудь определить, что я делаю неправильно?

Я предполагаю, что кэширование не является проблемой, поскольку я выполняю запись в память.

EDIT: Это была отладочная сборка. Per Laserallan предположил, что я сделал сборку релизов:

[Boost] Elapsed time:  0.266 seconds
[Native]Elapsed time:  0.016 seconds

Гораздо ближе. Но от 16 до 1 мне все равно кажется.

Ну, нет окончательного ответа, но я собираюсь перейти и оставить свой настоящий код с родными массивами на данный момент.

Принятие ответа Laserallan, потому что это был самый большой недостаток в моем тесте.

Спасибо всем.

4b9b3361

Ответ 1

Вы создаете выпуск или отлаживаете?

Если вы работаете в режиме отладки, массив boost может быть очень медленным, потому что магия шаблонов не встроена должным образом, что дает много накладных расходов в вызовах функций. Я не уверен, как многомерный массив реализован, так что это может быть полностью отключено:)

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

Попробуйте переключить порядок циклов X и Y и посмотрите, получаете ли вы что-либо. Здесь есть информация о порядке хранения: http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html

EDIT: Поскольку вы, кажется, используете двухмерный массив для обработки изображений, вам может быть интересно проверить библиотеку обработки изображений ускорения gil.

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

Ответ 2

На моей машине с помощью

g++ -O3 -march=native -mtune=native --fast-math -DNDEBUG test.cpp -o test && ./test

Я получаю

[Boost] Elapsed time:  0.020 seconds
[Native]Elapsed time:  0.020 seconds

Однако меняя const int ITERATIONS на 5000, я получаю

[Boost] Elapsed time:  0.240 seconds
[Native]Elapsed time:  0.180 seconds

затем с ITERATIONS назад до 500, но X_SIZE и Y_SIZE, установленным на 400, я получаю гораздо более существенную разницу

[Boost] Elapsed time:  0.460 seconds
[Native]Elapsed time:  0.070 seconds

наконец, инвертируя внутренний цикл для случая [Boost], чтобы он выглядел как

    for (int x = 0; x < X_SIZE; ++x)
    {
        for (int y = 0; y < Y_SIZE; ++y)
        {

и сохраняя ITERATIONS, X_SIZE и Y_SIZE до 500, 400 и 400, я получаю

[Boost] Elapsed time:  0.060 seconds
[Native]Elapsed time:  0.080 seconds

Если я инвертирую внутренний цикл также для случая [Native] (так что это неверный порядок для этого случая), я получаю неудивительно,

[Boost] Elapsed time:  0.070 seconds
[Native]Elapsed time:  0.450 seconds

Я использую gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 в Ubuntu 10.10

Итак, в заключение:

  • При правильной оптимизации boost:: multi_array выполняет свою работу как ожидалось
  • Порядок, по которому вы получаете доступ к своим данным, имеет значение

Ответ 3

Ваш тест испорчен.

  • В сборке DEBUG boost:: MultiArray не хватает прохода оптимизации, которого это очень необходимо. (Гораздо больше, чем собственный массив)
  • В сборке RELEASE ваш компилятор будет искать код, который можно удалить напрямую, и большая часть вашего кода находится в этой категории.

То, что вы, вероятно, видите, является результатом вашего оптимизирующего компилятора, видя, что большинство или все ваши петли "собственного массива" могут быть удалены. То же самое теоретически справедливо для ваших циклов boost:: MultiArray, но MultiArray, вероятно, достаточно сложный, чтобы победить ваш оптимизатор.

Внесите это небольшое изменение в свой тестовый стенд, и вы увидите более верные результаты: измените оба события "= 2.345" на "*= 2.345" и снова скомпилируйте с оптимизацией, Это не позволит вашему компилятору обнаружить, что внешний цикл каждого теста является избыточным.

Я сделал это и получил сравнение скорости ближе к 2: 1.

Ответ 4

Рассмотрим вместо этого Blitz ++. Я попробовал Blitz, и его производительность сравнима с массивом C-стиля!

Проверьте свой код с добавлением Blitz ниже:


#include <windows.h>
#define _SCL_SECURE_NO_WARNINGS
#define BOOST_DISABLE_ASSERTS 
#include <boost/multi_array.hpp>
#include <blitz/array.h>

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

    // Create the boost array
    typedef boost::multi_array<double, 2> ImageArrayType;
    ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);


    //------------------Measure boost----------------------------------------------
    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)
            {
                boostMatrix[x][y] = 2.345;
            }
        }
    }
    endTime = ::GetTickCount();
    printf("[Boost] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);

    //------------------Measure blitz-----------------------------------------------
    blitz::Array<double, 2> blitzArray( 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)
            {
                blitzArray(x,y) = 2.345;
            }
        }
    }
    endTime = ::GetTickCount();
    printf("[Blitz] Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);


    //------------------Measure native-----------------------------------------------
    // 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; ++y)
        {
            for (int x = 0; x < X_SIZE; ++x)
            {
                nativeMatrix[x + (y * X_SIZE)] = 2.345;
            }
        }
    }
    endTime = ::GetTickCount();
    printf("[Native]Elapsed time: %6.3f seconds\n", (endTime - startTime) / 1000.0);



    return 0;
}

Вот результат отладки и выпуска.

DEBUG:

Boost  2.093 secs 
Blitz  0.375 secs 
Native 0.078 secs

RELEASE:

Boost  0.266 secs
Blitz  0.016 secs
Native 0.015 secs

Я использовал компилятор MSVC 2008 SP1 для этого.

Можно ли попрощаться с C-stlye массивом? = Р

Ответ 5

Мне интересно две вещи:

1) проверка границ: определите макрос препроцессора BOOST_DISABLE_ASSERTS перед включением multi_array.hpp в ваше приложение. Это отключает проверку привязки. не уверен, что это отключается, когда NDEBUG.

2) базовый индекс:  MultiArray может индексировать массивы из баз, отличных от 0. Это означает, что multi_array хранит базовое число (в каждом измерении) и использует более сложную формулу для получения точного местоположения в памяти, мне интересно, все ли это.

В противном случае я не понимаю, почему multiarray должен быть медленнее, чем C-массивы.

Ответ 6

Я смотрел на этот вопрос, потому что у меня был тот же вопрос. У меня были некоторые мысли, чтобы дать более строгий тест.

  • Как отмечал rodrigob, есть недостатки в порядке цикла, так что любые результаты в коде, который вы первоначально приложили, будут давать вводящие в заблуждение данные.
  • Кроме того, существуют массивы небольшого размера, которые устанавливаются с использованием констант. Компилятор может оптимизировать петли, когда на самом деле компилятор не будет знать размер массивов. Размеры массивов и количество итераций должны быть в рабочем состоянии на всякий случай.

На Mac, следующий код сконфигурирован для предоставления более значимых ответов. Здесь есть 4 теста.

#define BOOST_DISABLE_ASSERTS
#include "boost/multi_array.hpp"
#include <sys/time.h>
#include <stdint.h>
#include<string>

uint64_t GetTimeMs64()
{
  struct timeval tv;

  gettimeofday( &tv, NULL );

  uint64_t ret = tv.tv_usec;
  /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
  ret /= 1000;

  /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
  ret += ( tv.tv_sec * 1000 );

  return ret;

}


void function1( const int X_SIZE, const int Y_SIZE, const int ITERATIONS )
{

  double nativeMatrix1add[X_SIZE*Y_SIZE];

  for( int x = 0 ; x < X_SIZE ; ++x )
  {
    for( int y = 0 ; y < Y_SIZE ; ++y )
    {
      nativeMatrix1add[y + ( x * Y_SIZE )] = rand();
    }
  }

  // Create the native array
  double* __restrict const nativeMatrix1p = new double[X_SIZE * Y_SIZE];
  uint64_t startTime = GetTimeMs64();
  for( int i = 0 ; i < ITERATIONS ; ++i )
  {
    for( int xy = 0 ; xy < X_SIZE*Y_SIZE ; ++xy )
    {
      nativeMatrix1p[xy] += nativeMatrix1add[xy];
    }
  }
  uint64_t endTime = GetTimeMs64();
  printf( "[Native Pointer]    Elapsed time: %6.3f seconds\n", ( endTime - startTime ) / 1000.0 );

}

void function2( const int X_SIZE, const int Y_SIZE, const int ITERATIONS )
{

  double nativeMatrix1add[X_SIZE*Y_SIZE];

  for( int x = 0 ; x < X_SIZE ; ++x )
  {
    for( int y = 0 ; y < Y_SIZE ; ++y )
    {
      nativeMatrix1add[y + ( x * Y_SIZE )] = rand();
    }
  }

  // Create the native array
  double* __restrict const nativeMatrix1 = new double[X_SIZE * Y_SIZE];
  uint64_t startTime = GetTimeMs64();
  for( int i = 0 ; i < ITERATIONS ; ++i )
  {
    for( int x = 0 ; x < X_SIZE ; ++x )
    {
      for( int y = 0 ; y < Y_SIZE ; ++y )
      {
        nativeMatrix1[y + ( x * Y_SIZE )] += nativeMatrix1add[y + ( x * Y_SIZE )];
      }
    }
  }
  uint64_t endTime = GetTimeMs64();
  printf( "[Native 1D Array]   Elapsed time: %6.3f seconds\n", ( endTime - startTime ) / 1000.0 );

}


void function3( const int X_SIZE, const int Y_SIZE, const int ITERATIONS )
{

  double nativeMatrix2add[X_SIZE][Y_SIZE];

  for( int x = 0 ; x < X_SIZE ; ++x )
  {
    for( int y = 0 ; y < Y_SIZE ; ++y )
    {
      nativeMatrix2add[x][y] = rand();
    }
  }

  // Create the native array
  double nativeMatrix2[X_SIZE][Y_SIZE];
  uint64_t startTime = GetTimeMs64();
  for( int i = 0 ; i < ITERATIONS ; ++i )
  {
    for( int x = 0 ; x < X_SIZE ; ++x )
    {
      for( int y = 0 ; y < Y_SIZE ; ++y )
      {
        nativeMatrix2[x][y] += nativeMatrix2add[x][y];
      }
    }
  }
  uint64_t endTime = GetTimeMs64();
  printf( "[Native 2D Array]   Elapsed time: %6.3f seconds\n", ( endTime - startTime ) / 1000.0 );

}



void function4( const int X_SIZE, const int Y_SIZE, const int ITERATIONS )
{

  boost::multi_array<double, 2> boostMatrix2add( boost::extents[X_SIZE][Y_SIZE] );

  for( int x = 0 ; x < X_SIZE ; ++x )
  {
    for( int y = 0 ; y < Y_SIZE ; ++y )
    {
      boostMatrix2add[x][y] = rand();
    }
  }

  // Create the native array
  boost::multi_array<double, 2> boostMatrix( boost::extents[X_SIZE][Y_SIZE] );
  uint64_t startTime = GetTimeMs64();
  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] += boostMatrix2add[x][y];
      }
    }
  }
  uint64_t endTime = GetTimeMs64();
  printf( "[Boost Array]       Elapsed time: %6.3f seconds\n", ( endTime - startTime ) / 1000.0 );

}

int main( int argc, char* argv[] )
{

  srand( time( NULL ) );

  const int X_SIZE = std::stoi( argv[1] );
  const int Y_SIZE = std::stoi( argv[2] );
  const int ITERATIONS = std::stoi( argv[3] );

  function1( X_SIZE, Y_SIZE, ITERATIONS );
  function2( X_SIZE, Y_SIZE, ITERATIONS );
  function3( X_SIZE, Y_SIZE, ITERATIONS );
  function4( X_SIZE, Y_SIZE, ITERATIONS );

  return 0;
}
  • Один с только одномерным массивом с использованием [] с целочисленной математикой и двойным циклом

  • Один с одним и тем же одномерным массивом с приращением указателя

  • Многомерный массив C

  • Усиление multi_array

поэтому запустите из командной строки, запустите

./test_array xsize ysize iterations"

и вы можете получить представление о том, как будут работать эти подходы. Вот что я получил со следующими флагами компилятора:

g++4.9.2 -O3 -march=native -funroll-loops -mno-avx --fast-math -DNDEBUG  -c -std=c++11


./test_array 51200 1 20000
[Native 1-Loop ]    Elapsed time:  0.537 seconds
[Native 1D Array]   Elapsed time:  2.045 seconds
[Native 2D Array]   Elapsed time:  2.749 seconds
[Boost Array]       Elapsed time:  1.167 seconds

./test_array 25600 2 20000
[Native 1-Loop ]    Elapsed time:  0.531 seconds
[Native 1D Array]   Elapsed time:  1.241 seconds
[Native 2D Array]   Elapsed time:  1.631 seconds
[Boost Array]       Elapsed time:  0.954 seconds

./test_array 12800 4 20000
[Native 1-Loop ]    Elapsed time:  0.536 seconds
[Native 1D Array]   Elapsed time:  1.214 seconds
[Native 2D Array]   Elapsed time:  1.223 seconds
[Boost Array]       Elapsed time:  0.798 seconds

./test_array 6400 8 20000
[Native 1-Loop ]    Elapsed time:  0.540 seconds
[Native 1D Array]   Elapsed time:  0.845 seconds
[Native 2D Array]   Elapsed time:  0.878 seconds
[Boost Array]       Elapsed time:  0.803 seconds

./test_array 3200 16 20000
[Native 1-Loop ]    Elapsed time:  0.537 seconds
[Native 1D Array]   Elapsed time:  0.661 seconds
[Native 2D Array]   Elapsed time:  0.673 seconds
[Boost Array]       Elapsed time:  0.708 seconds

./test_array 1600 32 20000
[Native 1-Loop ]    Elapsed time:  0.532 seconds
[Native 1D Array]   Elapsed time:  0.592 seconds
[Native 2D Array]   Elapsed time:  0.596 seconds
[Boost Array]       Elapsed time:  0.764 seconds

./test_array 800 64 20000
[Native 1-Loop ]    Elapsed time:  0.546 seconds
[Native 1D Array]   Elapsed time:  0.594 seconds
[Native 2D Array]   Elapsed time:  0.606 seconds
[Boost Array]       Elapsed time:  0.764 seconds

./test_array 400 128 20000
[Native 1-Loop ]    Elapsed time:  0.536 seconds
[Native 1D Array]   Elapsed time:  0.560 seconds
[Native 2D Array]   Elapsed time:  0.564 seconds
[Boost Array]       Elapsed time:  0.746 seconds

Итак, я думаю, что можно с уверенностью сказать, что boost multi_array работает очень хорошо. Ничто не сравнится с одной оценкой цикла, но в зависимости от размера массива boost:: multi_array может бить стандартный c-массив с двойным циклом.

Ответ 7

Еще одна вещь, которую следует попробовать - использовать итераторы вместо прямого индекса для массива boost.

Ответ 8

Я бы ожидал, что multiarray будет столь же эффективным. Но я получаю аналогичные результаты на PPC Mac, используя gcc. Я также попробовал multiarrayref, так что обе версии использовали одно и то же хранилище без каких-либо различий. Это полезно знать, поскольку я использую multiarray в некоторых своих кодах и просто предполагал, что он похож на ручное кодирование.

Ответ 9

Думаю, я знаю, в чем проблема... может быть.

Чтобы реализация boost имела синтаксис типа: matrix [x] [y]. это означает, что матрица [x] должна возвращать ссылку на объект, который действует как столбец 1D массива, после чего ссылка [y] дает вам ваш элемент.

Проблема заключается в том, что вы выполняете итерацию в row major порядке (что типично в c/С++, так как собственные массивы являются основными строками IIRC. Компилятор должен повторно выполнить матрицу [x] для каждый y в этом случае. Если вы выполнили итерацию в главном порядке столбца при использовании матрицы boost, вы можете увидеть лучшую производительность.

Просто теория.

EDIT: в моей Linux-системе (с некоторыми незначительными изменениями) я опробовал свою теорию и продемонстрировал некоторое улучшение производительности за счет переключения x и y, но все еще медленнее, чем собственный массив. Это может быть простой проблемой, когда компилятор не может оптимизировать временный ссылочный тип.

Ответ 10

Создайте в режиме выпуска, используйте objdump и посмотрите на сборку. Они могут делать совершенно разные вещи, и вы сможете увидеть, какие оптимизации использует компилятор.

Ответ 11

Аналогичный вопрос был задан и ответил здесь:

http://www.codeguru.com/forum/archive/index.php/t-300014.html

Короткий ответ заключается в том, что компилятор проще всего оптимизировать простые массивы и не так просто оптимизировать версию Boost. Следовательно, конкретный компилятор не может давать Boost-версии все те же преимущества оптимизации.

Компиляторы также могут варьироваться в зависимости от того, насколько хорошо они будут оптимизированы в сравнении с тем, насколько они консервативны (например, с использованием шаблонного кода или других осложнений).

Ответ 12

Я тестировал на Mac OS Snow Leopard с помощью gcc 4.2.1

Debug:
[Boost] Elapsed time:  2.268 seconds
[Native]Elapsed time:  0.076 seconds

Release:
[Boost] Elapsed time:  0.065 seconds
[Native]Elapsed time:  0.020 seconds

Здесь приведен код (измененный так, что он может быть скомпилирован в Unix):

#define BOOST_DISABLE_ASSERTS
#include <boost/multi_array.hpp>
#include <ctime>

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

    // Create the boost array
    typedef boost::multi_array<double, 2> ImageArrayType;
    ImageArrayType boostMatrix(boost::extents[X_SIZE][Y_SIZE]);

    // Create the native array
    double *nativeMatrix = new double [X_SIZE * Y_SIZE];

    //------------------Measure boost----------------------------------------------
    startTime = clock();
    for (int i = 0; i < ITERATIONS; ++i)
    {
        for (int y = 0; y < Y_SIZE; ++y)
        {
            for (int x = 0; x < X_SIZE; ++x)
            {
                boostMatrix[x][y] = 2.345;
            }
        }
    }
    endTime = clock();
    printf("[Boost] Elapsed time: %6.3f seconds\n", (endTime - startTime) / (double)CLOCKS_PER_SEC);

    //------------------Measure native-----------------------------------------------
    startTime = clock();
    for (int i = 0; i < ITERATIONS; ++i)
    {
        for (int y = 0; y < Y_SIZE; ++y)
        {
            for (int x = 0; x < X_SIZE; ++x)
            {
                nativeMatrix[x + (y * X_SIZE)] = 2.345;
            }
        }
    }
    endTime = clock();
    printf("[Native]Elapsed time: %6.3f seconds\n", (endTime - startTime) / (double)CLOCKS_PER_SEC);

    return 0;
}

Ответ 13

Глядя на сборку, сгенерированную g++ 4.8.2, с помощью -O3 -DBOOST_DISABLE_ASSERTS и используя как operator(), так и [][] способы доступа к элементам, очевидно, что единственная дополнительная операция по сравнению с встроенными массивами и вычислением ручного индекса добавление основания. Я не оценил стоимость этого, хотя.

Ответ 14

Я изменил приведенный выше код в visual studio 2008 v9.0.21022 и применил подпрограммы контейнера из подпрограмм Numerical Recipe для C и С++

http://www.nrbook.com/nr3/, используя свои лицензированные подпрограммы dmatrix и MatDoub соответственно

dmatrix использует устаревший синтаксический оператор malloc и не рекомендуется... MatDoub использует команду New

Скорость в секундах находится в версии Release:

Boost: 0.437

Родной: 0,032

Численные рецепты C: 0.031

Численные рецепты С++: 0.031

Таким образом, из вышеприведенного блица выглядит как лучшая свободная альтернатива.

Ответ 15

Я скомпилировал код (с небольшими изменениями) в VС++ 2010 с включенной оптимизацией ( "Максимизировать скорость" вместе с встраиванием "Любые подходящие" функции и "Благоприятный быстрый код" ) и получил время 0,015/0,391. Я создал сборку и, хотя я ужасная сборка noob, там одна строка внутри цикла измерения форсирования, которая выглядит не очень хорошо:

call    [email protected][email protected]@@[email protected][email protected][email protected]@[email protected]@Z ; boost::multi_array_ref<double,2>::operator[]

Один из операторов [] не попал в очередь! Вызываемая процедура вызывает другой вызов, на этот раз multi_array::value_accessor_n<...>::access<...>():

call    [email protected][email protected][email protected][email protected]@[email protected]@[email protected][email protected][email protected][email protected]@[email protected]@[email protected][email protected]@[email protected][email protected][email protected][email protected]@[email protected]@@[email protected]@Z ; boost::detail::multi_array::value_accessor_n<double,2>::access<boost::detail::multi_array::sub_array<double,1>,double *>

В целом, две процедуры представляют собой довольно много кода для простого доступа к одному элементу массива. Мое общее впечатление состоит в том, что библиотека настолько сложна и высокоуровневаема, что Visual Studio не в состоянии ее оптимизировать так, как хотелось бы (плакаты с использованием gcc, по-видимому, получили лучшие результаты).

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

Ответ 16

Как ответил Родригоб, активация правильной оптимизации (по умолчанию GCC -O0) является ключом для получения хорошей производительности. Кроме того, я также провел тестирование с Blaze DynamicMatrix, которое дало дополнительное повышение производительности в 2 раза с точно такими же флагами оптимизации. https://bitbucket.org/account/user/blaze-lib/projects/BLAZE