2017-09-09 3 views
-1

Donc, j'écris un programme, où l'optimisation est un facteur clé. Cependant: lors de l'optimisation, je remarque une fonction que je considérais comme relativement simple, qui prenait trop de temps à fonctionner. D'autant plus que, en comparaison, une fonction beaucoup plus difficile prend beaucoup plus de temps.Des temps d'exécution étranges dans les boucles C++

Whole Relevant section

// Simple function 

int get_chunk_index(std::vector<Chunk> chunks, int x, int y) { 
    glm::vec3 target = glm::vec3(x * 40, 0, y * 40); 
    for (int i = 0; i < chunks.size(); i++) { 
     if (chunks[i].trans.GetPos() == target) { 
      return i; 
     } 
    } 
    return -1; 
} 

// End simple function 

Time in function

Si vous voulez plus des fonctions, ne hésitez pas à demander, mais il est tout à fait un grand programme, donc je ne peux pas comprendre tout ici.

PS: Les blocs ne font que de 0 à> 40 pouces.

+1

Essayez de retirer 'chunks.size()' de la boucle en l'assignant à une variable. Et que fait 'getPos()'? – Barmar

+2

Avez-vous essayé de remplacer 'std :: vector ' par 'const std :: vector &'? Cela devrait sauver un peu en permettant à la copie profonde d'être enlevée. – VermillionAzure

+1

Lier à pastebin est de mauvais style, car ce n'est pas sous le contrôle de ce site Web, et vous ou pastebin lui-même peut décider de l'enlever plus tard. Publier un échantillon autonome qui peut reproduire le problème que vous décrivez [dans le processus, vous pouvez trouver que vous résolvez le problème] –

Répondre

3

Quelques options simples.

1) chunks est passé en valeur, ce qui crée une copie complète du vecteur transmis. Essayez de passer par const référence (c'est-à-dire const std::vector<Chunk> &chunk) à la place.

2) Plutôt que de passer x et y, et la création d'un glm::vec3 (quel qu'il soit - il est non standard) d'eux, changer la fonction d'accepter un glm::vec3 par référence. Cela force l'appelant à créer l'objet, mais permet également à l'appelant de contrôler sa mise à jour (plutôt que de recréer un nouvel objet à chaque fois).

3) Prendre l'évaluation de chunks.size() en dehors de la boucle, et utiliser le pré-incrément (ne crée pas un provisoire) plutôt que le post-incrément.

std::size_t size = chunks.size(); 
for (int i = 0; i < size; ++i) { 
    if (chunks[i].trans.GetPos() == target) 
    { 
     return i; 
    } 
} 

4) Envisagez d'utiliser des itérateurs plutôt que l'indexation de tableaux.

std::vector<Chunk>::const_iterator i, begin = chunks.begin(), end = chunks.end(); 

for (i = begin; i != end; ++i) 
    if (i->trans.GetPos() == target) return std::distance(begin, i); 

ou (11 C++ et plus tard)

for (const auto &i : chunks) 
{ 
    if (i.trans.GetPos() == target) return std::distance(chunks.begin(), i); 
} 

5) Au lieu de passer du vecteur, passe ses beginend et itérateurs. Cela permettra plus de simplification de la boucle.

6) Vérifiez ce que fait la fonction getPos() appelée et optimisez-la.

7) Effectuez vos mesures de synchronisation avec l'optimisation activée, et faites-les sur un grand nombre d'appels de la fonction. Les mesures de performance des appels de fonction individuels ne signifient pas grand-chose en pratique (la gigue dans d'autres choses qui affectent la performance dominera vos mesures).

+0

Juste une note sur le "pré-incrément": tous les compilateurs modernes peuvent optimiser la génération de telles valeurs temporaires dans tous les cas, sauf les plus compliqués et complexes. [Personnellement, j'utiliserais les boucles de plage C++ 11 selon le paragraphe 4 (b), mais sans tenir compte des "temporaires"] –

+0

Pour les types de base, oui. Mais pas nécessairement pour les types définis par l'utilisateur qui fournissent des pré et post-incréments surchargés (la plupart des gens font cela pour que les opérateurs aient une sémantique "normale"), ce qui signifie un temporaire pour conserver la valeur précédente d'un post-incrément. t élimine nécessairement à moins d'avoir la visibilité de la définition de l'opérateur surchargé sur le site d'appel. Bien que les itérateurs d'un vecteur PEUVENT être (et sont souvent, dans la pratique) des pointeurs, rien ne les empêche d'être un type défini par l'utilisateur avec des opérateurs surchargés. – Peter

0

Il a fini par être simplement la copie profonde, comme Chunk est un assez grand fichier, et je n'ai pas remarqué la copie.

Code du travail:

// Simple function 

int get_chunk_index(std::vector<Chunk>& chunks, int x, int y) { 
    glm::vec3 target = glm::vec3(x * 40, 0, y * 40); 
    for (int i = 0; i < chunks.size(); i++) { 
     if (chunks[i].trans.GetPos() == target) { 
      return i; 
     } 
    } 
    return -1; 
} 

// End simple function