Test de Performance Java [dupliquer]


Cette question a déjà une réponse ici:

Je veux faire des tests de synchronisation sur une application Java. Voici ce que je fais actuellement:

long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");

Y a-t-il quelque chose de "faux" avec des tests de performance comme celui-ci? Quelle est la meilleure façon?

Double: Est-chronomètre l'analyse comparative acceptable?

Author: Chris W., 2009-01-15

9 answers

Le seul défaut de cette approche est que le temps "réel" que doSomething() prend pour s'exécuter peut varier énormément en fonction des autres programmes qui s'exécutent sur le système et de sa charge. Cela rend la mesure du rendement quelque peu imprécise.

Un moyen plus précis de suivre le temps nécessaire à l'exécution du code, en supposant que le code est mono-thread, est de regarder le temps CPU consommé par le thread pendant l'appel. Vous pouvez le faire avec les classes JMX; en particulier, avec ThreadMXBean. Vous pouvez récupérer une instance de ThreadMXBean de java.lang.management.ManagementFactory, et, si votre plate-forme prend en charge (la plupart le font), utiliser le getCurrentThreadCpuTime méthode à la place de System.currentTimeMillis pour faire un test similaire. Gardez à l'esprit que getCurrentThreadCpuTime indique le temps en nanosecondes, pas millisecondes.

Voici un exemple de méthode (Scala) qui pourrait être utilisé pour effectuer une mesure:

def measureCpuTime(f: => Unit): java.time.Duration = {

  import java.lang.management.ManagementFactory.getThreadMXBean
  if (!getThreadMXBean.isThreadCpuTimeSupported)
    throw new UnsupportedOperationException(
      "JVM does not support measuring thread CPU-time")

  var finalCpuTime: Option[Long] = None
  val thread = new Thread {
    override def run(): Unit = {
      f
      finalCpuTime = Some(getThreadMXBean.getThreadCpuTime(
        Thread.currentThread.getId))
    }
  }
  thread.start()

  while (finalCpuTime.isEmpty && thread.isAlive) {
    Thread.sleep(100)
  }

  java.time.Duration.ofNanos(finalCpuTime.getOrElse {
    throw new Exception("Operation never returned, and the thread is dead " +
      "(perhaps an unhandled exception occurred)")
  })
}

(N'hésitez pas à traduire ce qui précède en Java!)

Cette stratégie n'est pas parfaite, mais elle est moins sujette aux variations la charge du système.

 30
Author: MattK, 2017-11-17 21:01:20

Le code indiqué dans la question n'est pas un bon code de mesure de performance:

  1. Le compilateur peut choisir d'optimiser votre code en réorganisant les instructions. Oui, il peut le faire. Cela signifie que votre test entier pourrait échouer. Il peut même choisir d'intégrer la méthode testée et de réorganiser les instructions de mesure dans le code désormais intégré.

  2. Le hotspot peut choisir de réorganiser vos instructions, le code en ligne, les résultats du cache, retarder l'exécution...

  3. Même en supposant que le compilateur / hotspot ne vous a pas trompé, ce que vous mesurez est le "temps de mur". Ce que vous devriez mesurer, c'est le temps CPU (sauf si vous utilisez des ressources du système d'exploitation et souhaitez les inclure également ou si vous mesurez la contestation de verrouillage dans un environnement multithread).

La solution? Utilisez un vrai profileur. Il y a beaucoup autour, à la fois des profileurs gratuits et des démos / essais verrouillés de la force des publicités.

 16
Author: Ran Biron, 2009-01-15 20:23:44

L'utilisation d'un profileur Java est la meilleure option et vous donnera tous les renseignements dont vous avez besoin dans le code. à savoir Les Temps de réponse, les CallTraces de Thread, les Utilisations de la mémoire, etc

Je vais vous suggérer JENSOR, un profileur Java open source, pour sa facilité d'utilisation et sans frais généraux sur le processeur. Vous pouvez le télécharger, instrumenter le code et obtenir toutes les informations dont vous avez besoin sur votre code.

Vous pouvez le télécharger à partir de: http://jensor.sourceforge.net/

 2
Author: M.N, 2009-01-24 06:40:12

Gardez à l'esprit que la résolution de System.currentTimeMillis() varie entre les différents systèmes d'exploitation. Je crois que Windows est d'environ 15 msec. Donc, si votre doSomething() s'exécute plus rapidement que la résolution temporelle, vous obtiendrez un delta de 0. Vous pouvez exécuter doSomething() dans une boucle plusieurs fois, mais la JVM peut alors l'optimiser.

 1
Author: Steve Kuo, 2009-01-15 17:49:43

Eh bien, ce n'est qu'une partie des tests de performance. Selon la chose que vous testez, vous devrez peut-être examiner la taille du tas, le nombre de threads, le trafic réseau ou toute une série d'autres choses. Sinon j'utilise cette technique pour des choses simples que je veux juste voir combien de temps ils prennent pour s'exécuter.

 0
Author: Josh Harris, 2009-01-15 17:46:49

C'est bien lorsque vous comparez une implémentation à une autre ou essayez de trouver une partie lente dans votre code (bien que cela puisse être fastidieux). C'est une très bonne technique à connaître et vous l'utiliserez probablement plus que toute autre, mais familiarisez-vous également avec un outil de profilage.

 0
Author: Bill K, 2009-01-15 17:53:46

Avez-vous regardé les outils de profilage, netbeans et eclipse. Ces outils vous donnent une meilleure compréhension de ce qui occupe vraiment tout le temps dans votre code. J'ai trouvé des problèmes que je ne réalisais pas en utilisant ces outils.

 0
Author: Milhous, 2009-01-15 18:06:46

J'imagine que vous voudriez doSomething() avant de commencer à chronométrer aussi, de sorte que le code soit secoué et "réchauffé".

 0
Author: Kent Boogaart, 2011-09-28 00:03:02

Japex peut vous être utile, soit comme moyen de créer rapidement des benchmarks, soit comme moyen d'étudier les problèmes de benchmarking en Java via le code source.

 0
Author: Rich Apodaca, 2015-09-04 22:04:46