Vecteur vs les Performances de la baie
Dans un autre thread, j'ai commencé une discussion sur les Vecteurs et les Matrices, dans lequel j'ai été largement jouer l'avocat du diable, pour les boutons-poussoirs. Cependant, au cours de cette, je suis tombé sur un cas de test qui m'a un peu perplexe, et je voudrais avoir une vraie discussion à ce sujet, sur les "abus" je suis la pour jouer l'avocat du diable, de lancer un véritable débat sur ce thread est maintenant impossible. Cependant, l'exemple particulier m'a intrigué, et je ne peux pas l'expliquer à moi-même de manière satisfaisante.
La discussion est sur les performances générales du Vecteur vs Tableaux, en ignorant les éléments dynamiques. Ex: évidemment, l'utilisation constante de la push_back() dans un vecteur va le ralentir. Nous supposons que le vecteur et matrice sont pré-remplis avec les données. L'exemple que j'ai présenté, et modifiée par la suite par un individu dans le fil, est le suivant:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
const int ARRAY_SIZE = 500000000;
//http://stackoverflow.com/a/15975738/500104
template <class T>
class no_init_allocator
{
public:
typedef T value_type;
no_init_allocator() noexcept {}
template <class U>
no_init_allocator(const no_init_allocator<U>&) noexcept {}
T* allocate(std::size_t n)
{return static_cast<T*>(::operator new(n * sizeof(T)));}
void deallocate(T* p, std::size_t) noexcept
{::operator delete(static_cast<void*>(p));}
template <class U>
void construct(U*) noexcept
{
//libstdc++ doesn't know 'is_trivially_default_constructible', still has the old names
static_assert(is_trivially_default_constructible<U>::value,
"This allocator can only be used with trivally default constructible types");
}
template <class U, class A0, class... Args>
void construct(U* up, A0&& a0, Args&&... args) noexcept
{
::new(up) U(std::forward<A0>(a0), std::forward<Args>(args)...);
}
};
int main() {
srand(5); //I use the same seed, we just need the random distribution.
vector<char, no_init_allocator<char>> charArray(ARRAY_SIZE);
//char* charArray = new char[ARRAY_SIZE];
for(int i = 0; i < ARRAY_SIZE; i++) {
charArray[i] = (char)((i%26) + 48) ;
}
for(int i = 0; i < ARRAY_SIZE; i++) {
charArray[i] = charArray[rand() % ARRAY_SIZE];
}
}
Lorsque je l'exécute sur ma machine, j'ai le terminal de sortie. La première manche est avec le vecteur ligne sans commentaire, la seconde est la matrice ligne sans commentaire. J'ai utilisé le plus haut niveau d'optimisation, pour donner le vecteur le plus de chance de succès. Ci-dessous sont mes résultats, les deux premières courses de la gamme ligne sans commentaire, la deuxième à deux avec le vecteur ligne.
//Array run # 1
clang++ -std=c++11 -stdlib=libc++ -o3 some.cpp -o b.out && time ./b.out
real 0m20.287s
user 0m20.068s
sys 0m0.175s
//Array run # 2
clang++ -std=c++11 -stdlib=libc++ -o3 some.cpp -o b.out && time ./b.out
real 0m21.504s
user 0m21.267s
sys 0m0.192s
//Vector run # 1
clang++ -std=c++11 -stdlib=libc++ -o3 some.cpp -o b.out && time ./b.out
real 0m28.513s
user 0m28.292s
sys 0m0.178s
//Vector run # 2
clang++ -std=c++11 -stdlib=libc++ -o3 some.cpp -o b.out && time ./b.out
real 0m28.607s
user 0m28.391s
sys 0m0.178s
Que les piles de surpasser les vecteurs ne me surprend pas, cependant, que la différence est de l'ordre de 50% me surprend beaucoup, je m'attends à ce qu'ils seraient négligeables, et je me sens comme la nature de ce test m'être obscurcir la nature des résultats. Lorsque vous exécutez ce test sur le tableau des tailles plus petites, les différences de performances dissiper de façon spectaculaire.
Mon explication:
Supplémentaires de la mise en œuvre des instructions vectorielles sont à l'origine du vecteur instructions pour l'aligner dans la mémoire de mal, peut-être même sur cet exemple, un split à vraiment un mauvais point sur 2 différents "blocs". Ceci est à l'origine de la mémoire de sauter en arrière-et-vient entre les niveaux de cache vs cache de données vs cache d'instructions de plus en plus fréquemment que vous attendez. Je pense aussi que le compilateur LLVM peut-être exagérer les faiblesses, et de l'optimisation de mal, à cause de certains des plus récents de C++11 éléments, mais je n'ai aucune raison pour ces explications en dehors de l'hypothèse et de la conjecture.
Je suis intéressé si Un: que quelqu'un peut reproduire mes résultats et B: si quelqu'un a une meilleure explication de la façon dont l'ordinateur est en cours d'exécution cette référence et pourquoi vecteur est donc considérablement moins performants tableaux dans cette instance.
Mon set up: http://www.newegg.com/Product/Product.aspx?Item=N82E16834100226
-o3
devrait être -O3
, vous n'êtes pas à l'optimiser.Question intéressante, et tellement agréable de voir le code source, les drapeaux de compilation et de résultats, avec une explication détaillée. +1 pour une question posée. 🙂
Je ne vois pas la différence sur VC++
À l'aide de
-O3
et l'évolution is_trivially_default_constructible
à has_trivial_default_constructor
(à l'aide de libstdc++
), j'ai 0m26.250s pour le tableau et 0m27.438s vecteur, alors c'est plus ou moins la faible différence.Ce que vous décrivez est précisément ce que les optimisations devrait résoudre le problème.
OriginalL'auteur ChrisCM | 2013-05-08
Vous devez vous connecter pour publier un commentaire.
Je peux vous garantir que LLVM n'enfait misoptimize std::vector (si vous êtes, en fait, l'optimisation de la), au moins à partir de maintenant. Il n'est pas correctement inline de nombreux appels de fonction en cause. Vous obtiendrez de meilleures performances avec GCC.
Je collerais avec le Chiot sur celui-ci.
Je suis prêt à accepter cette réponse. Mon -O3 erreur a été la principale source de l'erreur, cependant g++ encore optimise l'ensemble de l'vecteur de questions, et je crois que ma version de LLVM est le coupable de l' ~10% de la faiblesse du vecteur, après l'optimisation appropriée.
Google a déclaré avoir 12% de perte avec LLVM, de sorte que c'est bien dans les limites prévues.
OriginalL'auteur Puppy
Une explication plus simple: vous êtes en train de construire avec des optimisations désactivé. Vous souhaitez
-O3
, pas-o3
.Je n'ai pas clang disponible à reproduire fidèlement vos tests, mais mes résultats sont comme suit:
Dans ce cas, ce n'est pas un errant drapeau. Vous êtes lui disant d'appeler la sortie
3
, puis en substituant qu'avec la plus tard-o b.out
.Haha, boiteux! Vous êtes de droite.
LLVM spécifiques misoptimization facilement compte de la fraction de la différence.#
Yep je suis d'accord, le point ici n'a corrigé le problème, mais le reste du problème est missoptimization par LLVM, clairement avec g++ les résultats sont, et doivent être, de plus en plus dépendante du système de bruit que toute différence dans les instructions ou d'assemblage.
OriginalL'auteur Mike Seymour