Question Comment écrire un micro-benchmark correct en Java?


Comment écrire (et exécuter) un micro-benchmark correct en Java?

Je cherche ici des exemples de code et des commentaires illustrant diverses choses à penser.

Exemple: Le benchmark doit-il mesurer le temps / l'itération ou les itérations / le temps, et pourquoi?

En relation: L'analyse comparative du chronomètre est-elle acceptable?


708
2018-02-02 17:39


origine


Réponses:


Conseils sur l'écriture de micro-repères des créateurs de Java HotSpot:

Règle 0: Lire un document de bonne réputation sur les JVM et micro-benchmarking. Un bon est Brian Goetz, 2005. Ne vous attendez pas trop à des micro-benchmarks; ils ne mesurent qu'une gamme limitée de caractéristiques de performance JVM.

Règle 1: Incluez toujours une phase d'échauffement qui exécute tout votre noyau de test, suffisamment pour déclencher toutes les initialisations et compilations avant la ou les phases de chronométrage. (Moins d'itérations est OK sur la phase de réchauffement La règle générale est de plusieurs dizaines de milliers d'itérations de boucle interne.)

Règle 2: Toujours courir avec -XX:+PrintCompilation, -verbose:gc, etc., afin que vous puissiez vérifier que le compilateur et d'autres parties de la JVM ne font pas de travail inattendu pendant votre phase de synchronisation.

Règle 2.1: Imprimez des messages au début et à la fin des phases de synchronisation et d'échauffement, afin de pouvoir vérifier qu'il n'y a pas de sortie de la règle 2 pendant la phase de chronométrage.

Règle 3: Soyez conscient de la différence entre -client et -server, et OSR et les compilations régulières. le -XX:+PrintCompilation flag signale les compilations OSR avec un at-sign pour indiquer le point d'entrée non-initial, par exemple: Trouble$1::run @ 2 (41 bytes). Préférer le serveur au client, et régulier à OSR, si vous êtes après les meilleures performances.

Règle 4: Soyez conscient des effets d'initialisation. N'imprimez pas pour la première fois pendant votre phase de chronométrage, car l'impression charge et initialise les classes. Ne chargez pas de nouvelles classes en dehors de la phase de démarrage (ou de la phase de génération de rapports finaux), à moins que vous ne testiez spécifiquement le chargement des classes (dans ce cas, chargez uniquement les classes de test). La Règle 2 est votre première ligne de défense contre de tels effets.

Règle 5: Soyez conscient des effets de désoptimisation et de recompilation. Ne prenez aucun chemin de code pour la première fois dans la phase de synchronisation, car le compilateur peut indésirable et recompiler le code, basé sur une hypothèse optimiste antérieure que le chemin n'allait pas être utilisé du tout. La Règle 2 est votre première ligne de défense contre de tels effets.

Règle 6: Utilisez les outils appropriés pour lire l'esprit du compilateur et attendez-vous à être surpris par le code qu'il produit. Inspectez le code vous-même avant de former des théories sur ce qui rend quelque chose de plus rapide ou plus lent.

Règle 7: Réduire le bruit dans vos mesures. Exécutez votre test sur une machine silencieuse et exécutez-le plusieurs fois, en rejetant les valeurs aberrantes. Utilisation -Xbatch pour sérialiser le compilateur avec l'application et considérez -XX:CICompilerCount=1 pour empêcher le compilateur de fonctionner en parallèle avec lui-même.

Règle 8: Utilisez une bibliothèque pour votre benchmark car elle est probablement plus efficace et a déjà été déboguée dans ce seul but. Tel que JMH, Étrier ou Les excellents repères UCSD de Bill et Paul pour Java.


657
2017-12-18 23:35



Je sais que cette question a été répondue, mais je voulais mentionner deux bibliothèques qui nous permettent d'écrire des micro-repères

Caliper de Google

Démarrer des tutoriels

  1. http://codingjunkie.net/micro-benchmarking-with-caliper/
  2. http://vertexlabs.co.uk/blog/caliper

JMH de OpenJDK

Démarrer des tutoriels

  1. Éviter les pièges de benchmarking sur la JVM
  2. http://nitschinger.at/Using-JMH-for-Java-Microbenchmarking
  3. http://java-performance.info/jmh/

211
2018-02-02 17:46



Les choses importantes pour les benchmarks Java sont:

  • Réchauffez le JIT d'abord en exécutant le code plusieurs fois avant de le chronométrer
  • Assurez-vous de l'avoir exécuté assez longtemps pour pouvoir mesurer les résultats en secondes ou (mieux) en dizaines de secondes
  • Alors que vous ne pouvez pas appeler System.gc() entre les itérations, c'est une bonne idée de l'exécuter entre les tests, de sorte que chaque test aura, espérons-le, un espace mémoire "propre" avec lequel travailler. (Oui, gc() est plus un indice qu'une garantie, mais c'est très probable que ça va vraiment ramasser les ordures dans mon expérience.)
  • J'aime afficher les itérations et le temps, et une note de temps / itération qui peut être mise à l'échelle de sorte que le «meilleur» algorithme obtienne un score de 1,0 et que d'autres soient notés de manière relative. Cela signifie que vous pouvez courir tout algorithmes pour un temps plus long, variant à la fois le nombre d'itérations et le temps, tout en obtenant des résultats comparables.

Je suis juste en train de bloguer sur la conception d'un cadre d'analyse comparative dans .NET. j'ai un couple de messages antérieurs qui peut vous donner quelques idées - tout ne sera pas approprié, bien sûr, mais il y en a peut-être.


70
2018-04-03 12:32



jmh est un ajout récent à OpenJDK et a été écrit par des ingénieurs de performance d'Oracle. Vaut certainement le coup d'oeil.

Le jmh est un faisceau Java pour la création, l'exécution et l'analyse de benchmarks nano / micro / macro écrits en Java et dans d'autres langages ciblant la JVM.

Des informations très intéressantes enfouies dans l'exemple teste les commentaires.

Voir également:


40
2018-02-02 19:54



Le benchmark devrait-il mesurer le temps / l'itération ou les itérations / temps, et pourquoi?

Cela dépend de ce que vous essayez de tester. Si vous êtes intéressé par la latence, utilisez time / itération et si vous êtes intéressé par le débit, utilisez des itérations / temps.


17
2018-02-02 18:00



Assurez-vous que vous utilisez en quelque sorte les résultats qui sont calculés dans le code de référence. Sinon, votre code peut être optimisé.


14
2018-02-02 17:57



Si vous essayez de comparer deux algorithmes, faites au moins deux tests sur chacun d'eux, en alternant l'ordre. c'est à dire.:

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

J'ai trouvé quelques différences notables (5-10% parfois) dans l'exécution du même algorithme dans différents passages.

Aussi, assurez-vous que n est très grand, de sorte que le temps d'exécution de chaque boucle est d'au moins 10 secondes. Plus il y a d'itérations, plus les chiffres sont significatifs dans votre temps de référence et plus les données sont fiables.


12
2018-02-02 17:46