Je joue avec un code de code calculant le temps nécessaire pour calculer un code Java pour obtenir un sentiment d'efficacité ou d'inefficacité de certaines fonctionnalités de Java. Cela je suis coincé maintenant avec un effet vraiment étrange que je ne peux tout simplement pas m'expliquer. Peut-être que quelqu'un d'entre vous peut m'aider à me comprendre.
private static int testFunc2(int test) {
return 5*test;
}
6 Réponses :
Ces points de repère sont difficiles car les compilateurs sont tellement intelligents. Une supposition: puisque le résultat de TestFunc () est ignorée, le compilateur pourrait l'optimiser complètement. Ajouter un compteur, quelque chose comme et, juste pour la minutie, faire un system.out.println (compteur) code> à la fin. P> p>
Mais cela ferait la première version plus rapide, mais ce n'est pas le cas.
Pourrait être la commande, comme suggéré par @Pelic. Pour une raison quelconque, JIT n'a pas optimisé l'appel la première fois, mais n'a compris la deuxième fois.
J'ai couru les deux sens localement et ça ne change pas les choses.
J'ai essayé d'inclure le comptoir et de changer de testfunc (3) sur TestFunc (fois). La première version (ne pas appeler testfunc ()) est toujours 2 fois plus lente.
C'est vraiment surprenant. Le bytecode généré est identique à l'exception du conditionnel, qui est Les résultats sont beaucoup plus sensibles si vous éteignez le JIT avec Je suppose qu'il peut optimiser le chèque dans le deuxième cas mais pas le premier (pour une raison quelconque). Même si cela signifie, il fait que le travail de la fonction, manque ce conditionnel rend les choses beaucoup plus rapides. Cela évite les stands de pipeline et tout cela. P> ifle code> vs ifne code>. P>
-Xint code>. La deuxième version est 2 fois plus lente. Donc, c'est à voir avec ce que l'optimisation JIT. P>
La chose est que cela dépend aussi de TestFunc (). Échangez le testfunc () de la première version avec quoi que ce soit d'autre, par exemple: Static privé Int Testfunc2 (int test) {Retour 5 * Test; } Cela entraînera le temps de calcul inférieur.
Eh bien, je suis heureux de ne pas avoir à gérer les optimisations de performance Java. Je l'ai essayé avec Java JDk 7 64 bits. Les résultats sont arbitraires;). Cela ne fait aucune différence qui répertorie que j'utilise ou si je cache le résultat de la taille () avant d'entrer dans la boucle. Également effacer entièrement la fonction de test ne fait presque aucune différence (il ne peut donc pas être une prédiction de branche frappée non plus). Les drapeaux d'optimisation améliorent les performances mais sont aussi arbitraires. p>
La seule conséquence logique ici est que le compilateur JIT est parfois capable d'optimiser la déclaration (ce qui n'est pas si difficile à être vrai), mais cela semble plutôt arbitraire. Une des nombreuses raisons pour lesquelles je préfère les langues comme C ++, où le comportement est au moins déterministe, même s'il est parfois arbitraire. P>
BTW dans la dernière éclipse, comme il était toujours sous Windows, exécutant ce code via IDE "RUN" (aucun débogage) est 10 fois plus lent que de l'exécuter à partir de la console ... P>
Lorsque le compilateur d'exécution peut calculer lorsque la condition est lorsque Certaines fonctions telles que p> Le compilateur essaie probablement de Optimiser (avant exécution), mais apparemment pas pour le cas d'un paramètre est transmis en tant qu'oquet et évalué dans un état conditionnel. P> Votre référence retourne des temps tels que P> testfunc code> évalue à une constante, je pense que cela n'évalue pas la boucle, ce qui explique le speed-up. Removelist.Size () == 0 code> La fonction testfunc (3) code> est évalué à une constante. Lorsque la condition est removeelist.size ()! = 0 code> Le code interne n'est jamais évalué, il ne peut pas être accéléré. Vous pouvez modifier votre code comme suit: p> testfunc () code> n'est pas initialement appelé, le compilateur d'exécution ne réalise pas que testfunc () code> évalue à une constante, il ne peut donc pas optimiser la boucle. p> time: 107
time: 106
time: 0
time: 0
...
Bien que cela ne soit pas directement lié à cette question, voici la manière dont vous seriez correctement micro référence le code à l'aide d'étrier. Vous trouverez ci-dessous une version modifiée de votre code afin qu'elle fonctionne avec étrier. Les boucles internes devaient être modifiées certaines de sorte que la machine virtuelle ne les optimise pas. Il est étonnamment intelligent à réaliser que rien ne se passait.
Il y a aussi beaucoup de nuances lors de l'analyse comparative du code Java. J'ai écrit à propos de certains des problèmes que j'ai rencontrés à Benchmark Java Matrix , telle Comme l'histoire passée peut effectuer des résultats actuels. Vous éviterez beaucoup de ces problèmes en utilisant Caliper. P>
Problèmes d'analyse comparative avec Java Matrix Benchmark < / p>
sortie: p>
Je ne pense pas que la question est de savoir comment microbenchmark mais explique le comportement observé. Mais vous frappez le long du chemin; C'est JIT optimisant quelque chose de manière inattendue.
Oui je suis d'accord. Je pensais que je pourrais signaler la bonne voie, car même après que ce code soit expliqué, il y aurait toujours des fluctuations étranges en raison de la configuration de la référence.
Merci pour la pointe avec étrier. Je vais utiliser ceci à l'avenir. Toutefois, la question reste la raison pour laquelle Java agit comme ceci. Dans votre exemple, vous avez changé le comportement en ajoutant un objet à la liste. Maintenant, la clause if-clause de Timesecondcase code> renvoie false. Et c'est toujours la seule version dans laquelle testfunc () n'est pas appelée qui est plus lente.
Les temps sont rapides irréalistes par itération. Cela signifie que le JIT a détecté que votre code ne fait rien et l'a éliminé. Les changements subtils peuvent confondre le JIT et il ne peut pas déterminer le code ne fait rien et cela prend un certain temps. p>
Si vous modifiez le test pour faire quelque chose de marginalement utile, la différence disparaîtra. P>
Et vous avez couru ce test plus d'une fois, et dans des commandes différentes? L'ordre n'aurait pas d'importance, mais juste pour s'assurer. Aussi, obtenez-vous (environ) les mêmes résultats avec Nanotime comme suggéré ci-dessous?
Ce type de micro-repère est une mauvaise idée. Réalisez également que le JIT peut prendre diverses décisions à des moments arbitraires et optimiser complètement votre code, si cela se rendit compte que rien ne se produit réellement.
Vous devriez utiliser System.NanOtime () pour mesurer l'exécution du code en Java. C'est plus précis. Plus de discussion dans cette question
Oui, je l'ai couru plusieurs fois et j'ai les mêmes résultats avec Nanotime. Pour le premier code: Time: 2256414917 Heure: 2256004749. Merci pour la pointe avec nanotime. Néanmoins, le premier code prend plus de 2 secondes, tandis que les autres exemples ne prennent même pas 10 miliques.
Vous devriez également poster un peu plus d'informations. Pour un test décent, utilisez Nanotime () et mesurez des microsecondes. De plus, invoquer Java d'IDes est généralement une mauvaise idée (au moins sur Windows). Utilisez une version récente, disons Java 7, et vous invoquerez votre fichier JAR à partir de la console avec quelque chose comme: Java -XX: + Aggressiveopts -xx: + UsefastAccessormethods -Server -Jar File
Les gars, si vous exécutez un programme et qu'il faut 30 secondes pour terminer, puis vous commencez un peu différent et complète dans <0,1 seconde ... Où avez-vous besoin exactement de plus Precision i>? Qui se soucie si le facteur est de 10 000 ou seulement 500, c'est une grande différence.
@yankee: c'est juste par principe d'utiliser nanotime () ^^. Peut-être que vous pourriez télécharger le code source SDK et regarder dans quelle taille () est vraiment ...
Qu'est-ce que
taille () code> n'a pas d'importance. Les deux extraits de code ont le même appel. La précision n'a pas d'importance. Ces drapeaux JVM ne comptent pas. Courir à travers une IDE peu importe. Il n'y a pas de problème de GC ici.@Owen: On dirait que vous êtes un programmeur pure Java ?!
La différence extrême dans les temps ne peut que (?) S'expliquer par le compilateur optimisant l'appel. Comme je l'ai suggéré dans ma réponse ci-dessous. Avez-vous essayé d'utiliser les résultats de l'appel afin qu'il ne puisse pas être optimisé pour comparer ???
Tout ce discours sur Nanotime () ou Millitime () a l'impression de discuter si vous devriez utiliser des aides à bande ou un chiffon pour aider une personne frappée par un tour anti-réservoir.