Question

Ma fonction sera appelée des milliers de fois. Si je veux le rendre plus rapide, va changer les variables de la fonction locale à statique de toute utilisation? Ma logique derrière cela est que, parce que les variables statiques sont persistantes entre les appels de fonction, ils sont attribués uniquement la première fois, et donc, chaque appel ultérieur n'allouer de la mémoire pour eux et deviendront plus vite, car l'étape d'allocation de mémoire ne se fait pas.

En outre, si ce qui précède est vrai, serait en utilisant des variables globales au lieu des paramètres plus rapide pour transmettre des informations à la fonction à chaque fois qu'il est appelé? Je pense que l'espace des paramètres est également attribué à chaque appel de fonction, pour permettre récursion (c'est pourquoi les utilisations de récursion plus de mémoire), mais étant donné que ma fonction n'est pas récursif, et si mon raisonnement est correct, décollent les paramètres seront en théorie faire il plus rapide.

Je sais que ces choses que je veux faire sont les habitudes de programmation horribles, mais s'il vous plaît, dites-moi s'il est sage. Je vais essayer de toute façon, mais s'il vous plaît me donner votre avis.

Était-ce utile?

La solution

Les frais généraux des variables locales est égal à zéro. Chaque fois que vous appelez une fonction, vous définissez déjà la pile pour les paramètres, les valeurs de retour, etc. Ajout de moyens variables locales que vous ajoutez un nombre légèrement plus grand au pointeur de la pile (un numéro qui est calculé au moment de la compilation) .

En outre, les variables locales sont probablement plus rapide en raison de la localité de cache.

Si vous n'appelez votre fonction « des milliers » de temps (pas des millions ou des milliards), alors vous devriez regarder votre algorithme pour les possibilités d'optimisation après vous avez exécuté un profileur.


Re: localité de cache ( lire la suite ): Accédés fréquemment les variables globales ont probablement la localité temporelle. Ils peuvent être également copiés sur un registre lors de l'exécution de la fonction, mais seront réécrites dans la mémoire (cache) après un retour de la fonction (sinon ils ne seraient pas accessibles à rien d'autre, les registres ne sont pas les adresses).

Les variables locales aura généralement à la fois localité temporelle et spatiale (ils obtiennent qu'en vertu d'être créé sur la pile). De plus, ils peuvent être « attribués » directement aux registres et ne jamais être écrit à la mémoire.

Autres conseils

La meilleure façon de savoir est d'exécuter effectivement un profileur. Cela peut être aussi simple que d'exécuter plusieurs tests chronométrés en utilisant les deux méthodes, puis en moyenne les résultats et la comparaison, ou vous pouvez envisager un outil de profilage complet qui se fixe à un processus et des graphiques sur l'utilisation de la mémoire au fil du temps et de la vitesse d'exécution.

Ne pas effectuer de micro-accordage de code aléatoire parce que vous avez un sentiment d'intestin, il sera plus rapide. Ont toutes les implémentations Compilateurs légèrement différentes des choses et ce qui est vrai sur un compilateur sur un environnement peut être faux sur une autre configuration.

Pour lutter contre ce commentaire au sujet de moins de paramètres: le processus de « inline » fonctions supprime essentiellement les frais généraux liés à l'appel d'une fonction. Les chances sont une petite fonction sera automatiquement en bordée par le compilateur, mais vous pouvez suggère une fonction inline être ainsi.

Dans une autre langue, C ++, la nouvelle norme en sortant des supports de transmission parfaite, et la sémantique de mouvement parfait avec des références rvalue qui supprime la nécessité de temporaires dans certains cas, ce qui peut réduire le coût d'appeler une fonction.

Je suppose que vous optimisez prématurément, cependant, vous ne devriez pas être ce qui concerne les performances jusqu'à ce que vous avez découvert vos véritables goulets d'étranglement.

ABSOLUMENT RIEN! La seule différence « performance » est lorsque les variables sont initialisés

    int anint = 42;
 vs
    static int anint = 42;

Dans le premier cas, le nombre entier sera réglé à 42 chaque fois que la fonction est appelée dans le second cas ot sera réglé à 42 lorsque le programme est chargé.

Cependant la différence est si trivial à être à peine perceptible. Son une idée fausse que le stockage doit être alloué pour les variables « automatiques » sur chaque appel. Ce n'est pas si C utilise l'espace déjà alloué dans la pile pour ces variables.

Les variables statiques peuvent réellement vous ralentir ses quelques optimisations ne sont pas possibles aggresive sur les variables statiques. De plus que les habitants sont dans une zone contiguë de la pile, ils sont plus faciles à mettre en cache efficacement.

Il n'y a pas une réponse à cette question. Elle varie avec la CPU, le compilateur, les drapeaux du compilateur, le nombre de variables locales que vous avez, ce qui fais avant de la CPU que vous appelez la fonction, et peut-être la phase de la lune.

Considérons deux extrêmes; si vous avez seulement un ou quelques variables locales, il / ils pourraient facilement être stockés dans des registres plutôt que d'être des emplacements de mémoire allouée à tous. Si le registre « pression » est suffisamment faible pour que cela peut se produire sans exécuter les instructions du tout.

A l'extrême opposé, il y a quelques machines (par exemple, les mainframes IBM) qui ne disposent pas des piles du tout. Dans ce cas, ce que nous penserions normalement comme cadres de pile sont effectivement attribués comme une liste chaînée sur le tas. Comme vous auriez probablement le deviner, cela peut être tout à fait lent.

En ce qui concerne l'accès aux variables, la situation est un peu similaire - l'accès à un registre de la machine est assez bien garanti pour être plus rapide que tout alloué dans la mémoire peut espérer possible. OTOH, il est possible d'accéder à des variables sur la pile d'être assez lent - il faut normalement quelque chose comme un accès indirect indexé, qui (en particulier avec les CPU plus) a tendance à être assez lent. OTOH, l'accès à un monde (qui est statique, même si son nom n'est pas globalement visible) nécessite généralement la formation d'une adresse absolue, qui pénalisent certains CPU dans une certaine mesure aussi bien.

Bottom line: même les conseils au profil de votre code peut être mal placé - la différence peut facilement être si petit que même un profileur ne détecter dependably, et que façon d'être sûr est d'examiner le langage assembleur qui est produit (et passer quelques années à apprendre le langage d'assemblage assez bien pour savoir quoi que ce soit dire lorsque vous faire regardez). L'autre côté de ceci est que lorsque vous avez affaire à une différence que vous ne pouvez pas mesurer même dependably, les chances que cela aura un effet significatif sur la vitesse de votre code est si éloigné qu'il est probablement pas la peine.

Il semble que la statique vs non-statique a été complètement couvert, mais sur le sujet des variables globales. Souvent, ceux-ci vont ralentir l'exécution des programmes plutôt que de l'accélérer.

La raison en est que les variables étroitement scope le rendre facile pour le compilateur d'optimiser fortement, si le compilateur doit regarder partout dans votre application pour les instances d'où une approche globale pourrait être utilisée, son optimisation ne sera pas aussi bonne.

Cette situation est aggravée lorsque vous introduisez des pointeurs, que vous avez le code suivant:

int myFunction()
{
    SomeStruct *A, *B;
    FillOutSomeStruct(B);
    memcpy(A, B, sizeof(A);
    return A.result;
}

le compilateur sait que le pointeur A et B ne peuvent jamais se chevauchent et il permet d'optimiser la copie. Si A et B sont alors globale qu'ils pourraient éventuellement pointent à chevauchement ou de mémoire identiques, cela signifie que le must du compilateur « jouer en toute sécurité », qui est plus lent. Le problème est généralement appelé « aliasing pointeur » et peut se produire dans beaucoup de situations non seulement des copies de mémoire.

http://en.wikipedia.org/wiki/Pointer_alias

Oui, en utilisant les variables statiques fera une fonction plus rapide un peu petit. Toutefois, cela causera des problèmes si jamais vous voulez faire votre programme multi-thread. Etant donné que les variables statiques sont partagés entre les appels de fonction, appeler la fonction simultanément dans différents fils se traduira par un comportement non défini. Multi-threading est le genre de chose que vous pouvez faire à l'avenir pour vraiment accélérer votre code.

La plupart des choses que vous avez mentionnées sont appelés micro-optimisations. En règle générale, se soucier de ce genre de choses est un mauvaise idée . Il rend votre code plus difficile à lire, et plus difficile à maintenir. Il est également très susceptible d'introduire des bugs. Vous aurez probablement obtenir plus pour votre argent faire des optimisations à un niveau supérieur.

Comme suggestions M2tM, l'exécution d'un profileur est aussi une bonne idée. Consultez gprof un qui est très facile à utiliser .

Vous pouvez toujours le temps de votre application pour déterminer vraiment ce qui est le plus rapide. Voici ce que je comprends: (tout cela dépend de l'architecture de votre processeur, btw)

fonctions C créer une trame de pile, qui est l'endroit où les paramètres transmis sont placés, et les variables locales sont mises, ainsi que le pointeur de retour à l'endroit où l'appelant appelle la fonction. Il n'y a pas d'allocation de gestion de la mémoire ici. Il habituellement un simple mouvement de pointeur et thats it. L'accès aux données de la pile est également assez rapide. Les pénalités sont généralement en jeu lorsque vous avez affaire avec des pointeurs.

En ce qui concerne les variables globales ou statiques, ils sont les mêmes ... du point de vue qu'ils vont être affectés dans la même région de la mémoire. L'accès à ceux-ci peuvent utiliser une autre méthode d'accès que les variables locales, dépend du compilateur.

La principale différence entre vos scénarios est empreinte mémoire, pas tant la vitesse.

Utilisation des variables statiques peuvent réellement faire votre code de manière significative plus lent . Les variables statiques doivent exister dans une région « données » de la mémoire. Pour utiliser cette variable, la fonction doit exécuter une instruction de charge à lire de la mémoire principale, ou une instruction de magasin pour écrire. Si cette région est pas dans le cache, vous perdez beaucoup de cycles. Une variable locale qui vit sur la pile la plus sûrement une adresse qui se trouve dans le cache, et peut-être même dans un registre cpu, apparaissant jamais dans la mémoire du tout.

Je suis d'accord avec les autres commentaires au sujet du profilage pour trouver des trucs comme ça, mais d'une manière générale, les variables statiques de la fonction devrait être plus lente. Si vous voulez, ce que vous êtes vraiment après est un global. Fonction / insérer un code statique des données pour vérifier si la chose a été initialisé déjà exécuté obtient chaque fois que votre fonction est appelée.

Le profilage ne peut pas voir la différence, et sachant désassembler ce qu'il faut pour pouvoir.

Je suppose que vous allez seulement pour obtenir une variation aussi bien que quelques cycles d'horloge par boucle (en moyenne en fonction du compilateur, etc.). Parfois, le changement sera une amélioration spectaculaire ou plus lent de façon spectaculaire, et ne sera pas en nécessairement parce que la maison des variables est déplacé vers / de la pile. Disons que vous enregistrez quatre cycles d'horloge par appel de fonction pour 10000 appels sur un processeur de 2 GHz. calcul très approximatif: 20 microsecondes sauvé. Est 20 microsecondes beaucoup ou un peu par rapport à votre temps d'exécution en cours?

Vous obtiendrez probablement plus une amélioration de la performance en faisant toutes vos omble chevalier et des variables courtes dans ints, entre autres. Micro-optimisation est une bonne chose de savoir, mais prend beaucoup de temps à expérimenter, le désassemblage, le calendrier de l'exécution de votre code, étant entendu que moins d'instructions ne signifie pas nécessairement plus rapide par exemple.

Prenez votre programme spécifique, désassembler la fois la fonction en question et le code qui l'appelle. Avec et sans électricité statique. Si vous gagnez seulement un ou deux instructions et c'est la seule optimisation que vous allez faire, il est sans doute pas la peine. Vous ne pouvez pas être en mesure de voir la différence tout profilage. Les changements dans où les lignes de cache frappé pourraient apparaître dans le profilage avant que les modifications du code par exemple.

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