Question

J'essaie de comparer les performances de boost::multi_array aux tableaux natifs alloués dynamiquement, avec le programme de test suivant :

#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;
}

J'obtiens les résultats suivants :

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

Je ne peux pas croire que les multi_arrays soient autant plus lents.Quelqu'un peut-il repérer ce que je fais de mal ?

Je suppose que la mise en cache n'est pas un problème puisque j'écris en mémoire.

MODIFIER:Il s'agissait d'une version de débogage.Selon Laserallan, j'ai fait une version de version :

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

Beaucoup plus près.Mais 16 contre 1 me semble quand même élevé.

Eh bien, pas de réponse définitive, mais je vais passer à autre chose et laisser mon vrai code avec des tableaux natifs pour le moment.

Accepter la réponse de Laserallan car c'était le plus gros défaut de mon test.

Merci à tous.

Était-ce utile?

La solution

Créez-vous une version ou un débogage?

Si vous utilisez le mode débogage, le tableau de surimpression peut être très lent, car la magie de leurs modèles n’est pas correctement insérée, ce qui entraîne beaucoup de surcharge lors des appels de fonction. Je ne suis pas sûr de savoir comment multi array est implémenté, donc ça pourrait être totalement inactif:)

Il existe peut-être une différence dans l'ordre de stockage, vous pouvez donc avoir votre image stockée colonne par colonne et l'écrire ligne par ligne. Cela donnerait un mauvais comportement de cache et pourrait ralentir les choses.

Essayez de changer l’ordre des boucles X et Y et voyez si vous gagnez quelque chose. Il y a quelques informations sur la commande de stockage ici: http://www.boost.org/doc/libs /1_37_0/libs/multi_array/doc/user.html

EDIT: Étant donné que vous semblez utiliser le tableau à deux dimensions pour le traitement des images, la bibliothèque de traitement d’images Boosts peut vous intéresser gil .

Il se peut que des tableaux avec moins de frais généraux fonctionnent parfaitement pour votre situation.

Autres conseils

Sur ma machine avec

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

je reçois

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

Cependant changer const int ITERATIONS à 5000 je reçois

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

puis avec ITERATIONS retour à 500 mais X_SIZE et Y_SIZE réglé sur 400 j'obtiens une différence beaucoup plus significative

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

finalement inverser la boucle interne pour le [Boost] cas afin qu'il ressemble à

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

et en conservant [Native], gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 et <=> à <=>, <=> et <=> je reçois

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

Si j'inverse également la boucle interne dans le cas <=> (il est donc dans le mauvais ordre pour ce cas), je reçois, sans surprise,

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

J'utilise <=> sur Ubuntu 10.10

Donc en conclusion:

  • Avec une optimisation appropriée boost :: multi_array fait son travail comme prévu
  • L'ordre dans lequel vous accédez à vos données n'a pas d'importance

Votre test est défectueux.

  • Dans une version DEBUG, boost :: MultiArray ne dispose pas de la passe d'optimisation dont il a cruellement besoin. (Bien plus qu’un tableau natif ne le ferait)
  • Dans une version RELEASE, votre compilateur recherchera du code pouvant être supprimé et la majorité de votre code se trouve dans cette catégorie .

Ce que vous êtes susceptible de voir est le résultat de votre compilateur d'optimisation ayant constaté que la plupart ou la totalité de votre & "; tableau natif &"; les boucles peuvent être enlevées. Il en va théoriquement de même pour vos boucles boost :: MultiArray, mais MultiArray est probablement assez complexe pour vaincre votre optimiseur.

Faites ce petit changement sur votre banc d'essai pour obtenir des résultats plus réalistes: modifiez les deux occurrences de & "; = 2.345 &"; avec " *= 2.345 " et compiler à nouveau avec des optimisations. Cela empêchera votre compilateur de découvrir que la boucle externe de chaque test est redondante.

Je l'ai fait et j'ai obtenu une comparaison de vitesse plus proche de 2: 1.

Je me demande deux choses:

1) vérification des limites: Définissez la macro de préprocesseur BOOST_DISABLE_ASSERTS avant d'inclure multi_array.hpp dans votre application. Cela désactive la vérification liée. je ne sais pas si cela est désactivé lorsque NDEBUG est activé.

2) indice de base:  MultiArray peut indexer des tableaux à partir de bases différentes de 0. Cela signifie que multi_array stocke un numéro de base (dans chaque dimension) et utilise une formule plus compliquée pour obtenir l'emplacement exact en mémoire. Je me demande s'il ne s'agit que de cela.

Sinon, je ne comprends pas pourquoi le multi-tableau doit être plus lent que le C-array.

Pensez à utiliser Blitz ++ à la place. J'ai essayé Blitz, et ses performances sont comparables à celles d'un tableau de style C!

Vérifiez votre code avec Blitz ajouté ci-dessous:

#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;
}

Voici le résultat du débogage et de la libération.

DÉBOGAGE:

Boost  2.093 secs 
Blitz  0.375 secs 
Native 0.078 secs

LIBERATION:

Boost  0.266 secs
Blitz  0.016 secs
Native 0.015 secs

J'ai utilisé le compilateur MSVC 2008 SP1 pour cela.

Pouvons-nous maintenant dire au revoir à C-stlye array? = p

Je regardais cette question parce que j'avais la même question. J'ai eu quelques idées pour faire un test plus rigoureux.

  1. Comme rodrigob a mis en évidence des failles dans l'ordre des boucles telles que tout résultat dans le code que vous avez initialement joint donnera des données trompeuses
  2. De plus, des tableaux de taille plutôt petite sont définis à l'aide de constantes. Le compilateur peut optimiser les boucles alors qu’en réalité, il ne connaîtra pas la taille des tableaux. La taille des tableaux et le nombre d’itérations doivent être des entrées d’exécution au cas où.

Sur un Mac, le code suivant est configuré pour donner des réponses plus significatives. Il y a 4 tests ici.

#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;
}
  1. Un avec un tableau à une seule dimension utilisant le [] avec un nombre entier et une boucle double

  2. Un avec le même tableau unidimensionnel utilisant l'incrémentation de pointeur

  3. Un tableau C multidimensionnel

  4. Un boost multi_array

alors exécutez à partir d'une ligne de commande, exécutez

./test_array xsize ysize iterations"

et vous pouvez avoir une bonne idée de la performance de ces approches. Voici ce que j'ai obtenu avec les drapeaux suivants du compilateur:

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

Donc, je pense qu’il est prudent de dire que le boost multi_array fonctionne assez bien. Rien ne vaut une évaluation à boucle unique, mais en fonction de la dimension du tableau, boost :: multi_array peut battre un tableau C standard avec une double boucle.

Une autre chose à essayer est d'utiliser des itérateurs au lieu d'un index simple pour le tableau de boost.

Je m'attendais à ce que la multi-matrice soit aussi efficace. Mais je reçois des résultats similaires sur un Mac PPC utilisant gcc. J'ai aussi essayé multiarrayref, de sorte que les deux versions utilisaient le même stockage sans aucune différence. C’est une bonne chose à savoir, car j’utilise le multi-tableau dans certains de mes codes et je suppose que c’est similaire au codage manuel.

Je pense connaître le problème ... peut-être.

Pour que l'implémentation boost ait une syntaxe telle que: matrix [x] [y]. cela signifie que matrix [x] doit renvoyer une référence à un objet qui agit comme un tableau 1D colonne , auquel référence [y] vous donne votre élément.

Le problème ici est que vous effectuez une itération dans l'ordre de la ligne principale (ce qui est typique en c / c ++, car les tableaux natifs sont des lignes principales, le code IIRC. Le compilateur doit réexécuter la matrice [x] pour Si vous avez itéré dans l'ordre des colonnes lors de l'utilisation de la matrice boost, vous obtiendrez peut-être de meilleures performances.

Juste une théorie.

EDIT: sur mon système Linux (avec quelques modifications mineures), j’ai testé ma théorie et présenté une amélioration des performances en commutant x et y, mais c’était toujours plus lent qu’un tableau natif. Cela pourrait être un simple problème du compilateur ne pouvant pas optimiser le type de référence temporaire.

Construisez en mode release, utilisez objdump et regardez l'assembly. Ils font peut-être des choses complètement différentes et vous pourrez voir quelles optimisations le compilateur utilise.

Une question similaire a été posée et répondue ici:

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

La réponse courte est qu’il est plus facile pour le compilateur d’optimiser les tableaux simples, et pas si facile d’optimiser la version de Boost. Par conséquent, un compilateur particulier peut ne pas offrir à la version Boost les mêmes avantages en termes d'optimisation.

Les compilateurs peuvent également varier en fonction de leur optimisation par rapport à leur prudence (par exemple, avec du code basé sur un modèle ou d’autres complications).

J'ai testé sur un Mac OS Snow Leopard avec 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

Voici le code (modifié pour pouvoir être compilé sous 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;
}

En regardant l'assemblage généré par g ++ 4.8.2 avec -O3 -DBOOST_DISABLE_ASSERTS et en utilisant les moyens operator() et [][] pour accéder aux éléments, il est évident que la seule opération supplémentaire par rapport aux tableaux natifs et au calcul d'index manuel est l'ajout de la base. Je n'ai cependant pas mesuré le coût de ceci.

J'ai modifié le code ci-dessus dans visual studio 2008 v9.0.21022 et appliqué les routines de conteneur à partir des routines de recette numérique pour C et C ++

http://www.nrbook.com/nr3/ en utilisant leurs routines sous licence, dmatrix et MatDoub respectivement

dmatrix utilise l'opérateur de malloc de syntaxe obsolète et n'est pas recommandé ... MatDoub utilise la commande New

La vitesse en secondes est dans la version Release:

Boost: 0.437

Natif: 0.032

Recettes numériques C: 0.031

Recettes numériques C ++: 0.031

Donc, à partir du blitz ci-dessus, cela ressemble à la meilleure alternative gratuite.

J'ai compilé le code (avec de légères modifications) sous VC++ 2010 avec l'optimisation activée ("Maximiser la vitesse" avec l'intégration des fonctions "Toutes les fonctions appropriées" et "Favoriser le code rapide") et j'ai obtenu des temps 0,015/0,391.J'ai généré une liste d'assemblage et, bien que je sois un terrible novice en assemblage, il y a une ligne à l'intérieur de la boucle de mesure de boost qui ne me semble pas bonne :

call    ??A?$multi_array_ref@N$01@boost@@QAE?AV?$sub_array@N$00@multi_array@detail@1@H@Z ; boost::multi_array_ref<double,2>::operator[]

L'un des opérateurs [] n'a pas été intégré !La procédure appelée effectue un autre appel, cette fois à multi_array::value_accessor_n<...>::access<...>():

call    ??$access@V?$sub_array@N$00@multi_array@detail@boost@@PAN@?$value_accessor_n@N$01@multi_array@detail@boost@@IBE?AV?$sub_array@N$00@123@U?$type@V?$sub_array@N$00@multi_array@detail@boost@@@3@HPANPBIPBH3@Z ; boost::detail::multi_array::value_accessor_n<double,2>::access<boost::detail::multi_array::sub_array<double,1>,double *>

Au total, les deux procédures représentent beaucoup de code pour accéder simplement à un seul élément du tableau.Mon impression générale est que la bibliothèque est si complexe et de haut niveau que Visual Studio est incapable de l'optimiser autant que nous le souhaiterions (les affiches utilisant gcc ont apparemment obtenu de meilleurs résultats).

À mon humble avis, un bon compilateur aurait vraiment dû intégrer et optimiser les deux procédures - les deux sont assez courtes et simples, ne contiennent aucune boucle, etc.Beaucoup de temps peut être perdu simplement à transmettre leurs arguments et leurs résultats.

Comme l'a répondu rodrigob, l'activation de l'optimisation appropriée (la valeur par défaut de GCC est -O0) est la clé pour obtenir de bonnes performances. De plus, j’ai également testé avec Blaze DynamicMatrix , qui a généré une Facteur 2 amélioration des performances avec exactement les mêmes drapeaux d'optimisation. https://bitbucket.org/account/user/blaze-lib/projects/ BLAZE

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top