[JAVA] J'ai essayé de mesurer et de comparer la vitesse de Graal VM avec JMH

environnement

Problème grossier de la mesure précédente

[Article précédent](https://qiita.com/kinshotomoya/items/39a821dd6a6a52202c0a#%E5%AE%9F%E9%9A%9B%E3%81%AB%E4%BD%BF%E3%81%A3 % E3% 81% A6% E3% 81% BF% E3% 82% 8B), et la comparaison de vitesse entre GraalVm et JVM standard a été effectuée.

Cependant, comme le temps de compilation, le temps de préchauffage et le temps d'exécution pur étaient mélangés et mesurés, il n'a pas été possible de faire une comparaison de vitesse pure de Graal lui-même.

Ce que je veux faire cette fois, c'est une comparaison de vitesse entre Graal de GraalVM et le compilateur C2 de JVM standard.

Par conséquent, nous faisons la distinction entre la compilation (génération de fichier de classe), le préchauffage et le temps d'exécution pur, et comparons le temps d'exécution pur.

Problèmes spécifiques

1. Le temps de compilation (génération du fichier de classe) a également été inclus.

Lors de l'exécution avec sbt, avant de l'exécuter, générez un fichier de classe de mixage puis mesurez.

$ sbt compile
$ sbt run

2. Le traitement de préchauffage et le traitement post-compilation ont été mesurés dans un désordre.

Comme je l'ai écrit dans cet article, la JVM exécute d'abord (réchauffe) le fichier de classe sur l'interpréteur et rassemble les informations nécessaires à la compilation. Le compilateur JIT est conçu pour compiler la méthode cible.

** Pour mesurer la vitesse d'exécution pure du compilateur Graal ou C2, vous devez réchauffer la méthode cible-> mesurer la vitesse après la compilation. ** **

Selon ce livre, le seuil pour passer de l'interpréteur du compilateur JIT au compilateur JIT est de 8000 fois. En d'autres termes, si vous exécutez (réchauffez) une méthode 8000 fois ou plus, la méthode sera compilée par le compilateur JIT, vous mesurerez donc la vitesse du code compilé.

Mesurer la vitesse à l'aide de JMH

La dernière fois, la mesure a été effectuée avec la commande / usr / bin / time. Cependant, comme il n'est pas possible de faire une comparaison de vitesse pure, JMH est utilisé pour obtenir des valeurs précises.

Il y a bibliothèque sbt, donc je l'ai utilisée.

Code à mesurer

Un programme qui lit des phrases en anglais à partir d'un fichier texte et recrache les 10 mots les plus fréquemment utilisés.

├── resources
│   └── GraalTest.txt
└── scala
    └── graal
        └── Performance.scala

fichier texte. J'ai apporté une phrase en anglais appropriée.

Graal.txt


When people talk about Japan, they would always think about how innovative and technological this country gets! Or how pretty and neat the country is! Last but not the least, fashion, Cosplay and hype beast were always a big thing in the city of Japan. Coming to Japan with the intention of tourism would have been a great experience. Different culture. You can find a lot of unique things they sell in Japan! But as you live in Japan, you interact with the locals and everything doesn’t seem the way you thought of Japan.

La taille est 525B.

$ ll
-rw-r--r--  1 kinsho  staff   525B  6 14 10:18 GraalTest.txt

Dans la bibliothèque JMH, les options de mesure peuvent être spécifiées avec des annotations. Il a été défini comme suit.

Performance.scala



package graal

import java.util.concurrent.TimeUnit

import org.openjdk.jmh.annotations._

import scala.annotation.tailrec
import scala.io.BufferedSource

//Spécifiez le nombre de fourches
//La valeur par défaut est 5
@Fork(1)
@Warmup(iterations = 1, batchSize = 10000)
@Measurement(iterations = 30, batchSize = 10000)
//Mesurer le temps d'exécution par exécution
@BenchmarkMode(Array(Mode.SingleShotTime))
//L'unité de mesure est la ms
@OutputTimeUnit(TimeUnit.MILLISECONDS)
class GraalTest {

  //Cibler cette méthode
  @Benchmark
  def run = {
    val fileName: String = "GraalTest.txt"
    val encode: String = "UTF-8"
    val source: BufferedSource = scala.io.Source.fromResource(fileName)
    val lines: Iterator[String] = source.getLines()
    val sortedTextList = lines.toList.mkString(" ").split(" ").sorted.toList
    val value = createMap(sortedTextList)
    val top10Words = value.toList.sortBy(_._2).reverse.take(10)
  }

  private def createMap(wordList: List[String]): Map[String, Long] = {
    @tailrec
    def loop(list: List[String], acc: Map[String, Long]): Map[String, Long] = {
      list match {
        case head :: tail if acc.isEmpty => {
          loop(tail, acc + (head -> 1L))
        }
        case head :: tail => {
          acc.get(head) match {
            case Some(value) => {
              loop(tail, acc.updated(head, value + 1L))
            }
            case None => {
              loop(tail, acc + (head -> 1L))
            }
          }
        }
        case head :: Nil => {
          acc.get(head) match {
            case Some(value) => {
              acc.updated(head, value + 1L)
            }
            case None => {
              acc + (head -> 1L)
            }
          }
        }
        case Nil => acc
      }
    }
    loop(wordList, Map.empty[String, Long])
  }
}


Exécuter sur JVM standard

Tout d'abord, compilez

sbt:jitCompiler> jmh:compile
[info] Compiling 3 Scala sources to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/classes ...
...
[info] Compiling 5 Java sources to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/classes ...
[success] Total time: 5 s, completed 2020/06/14 12:08:28

En fait, exécutez. À partir de «[info] # Version de la machine virtuelle: JDK 1.8.0_232, VM serveur OpenJDK 64 bits, 25.232-b09», vous pouvez voir qu'elle s'exécute en utilisant la JVM standard.

sbt:jitCompiler> jmh:run
[info] running (fork) org.openjdk.jmh.Main
[info] # JMH version: 1.21
[info] # VM version: JDK 1.8.0_232, OpenJDK 64-Bit Server VM, 25.232-b09
[info] # VM invoker: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/bin/java
[info] # VM options: <none>
[info] # Warmup: 1 iterations, single-shot each, 10000 calls per op
[info] # Measurement: 30 iterations, single-shot each, 10000 calls per op
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread
[info] # Benchmark mode: Single shot invocation time
[info] # Benchmark: graal.GraalTest.run
[info] # Run progress: 0.00% complete, ETA 00:00:00
[info] # Fork: 1 of 1
[info] # Warmup Iteration   1: 1075.011 ms/op
[info] Iteration   1: 555.518 ms/op
[info] Iteration   2: 634.679 ms/op
[info] Iteration   3: 552.381 ms/op
[info] Iteration   4: 687.170 ms/op
[info] Iteration   5: 538.699 ms/op
[info] Iteration   6: 537.693 ms/op
[info] Iteration   7: 622.123 ms/op
[info] Iteration   8: 801.559 ms/op
[info] Iteration   9: 611.831 ms/op
[info] Iteration  10: 567.022 ms/op
[info] Iteration  11: 590.506 ms/op
[info] Iteration  12: 666.859 ms/op
[info] Iteration  13: 564.290 ms/op
[info] Iteration  14: 552.446 ms/op
[info] Iteration  15: 713.195 ms/op
[info] Iteration  16: 781.514 ms/op
[info] Iteration  17: 685.628 ms/op
[info] Iteration  18: 570.931 ms/op
[info] Iteration  19: 557.543 ms/op
[info] Iteration  20: 559.926 ms/op
[info] Iteration  21: 677.823 ms/op
[info] Iteration  22: 551.438 ms/op
[info] Iteration  23: 564.687 ms/op
[info] Iteration  24: 560.043 ms/op
[info] Iteration  25: 553.672 ms/op
[info] Iteration  26: 548.359 ms/op
[info] Iteration  27: 777.705 ms/op
[info] Iteration  28: 794.434 ms/op
[info] Iteration  29: 917.850 ms/op
[info] Iteration  30: 553.160 ms/op
[info] Result "graal.GraalTest.run":
[info]   N = 30
[info]   mean =    628.356 ±(99.9%) 67.159 ms/op
[info]   Histogram, ms/op:
[info]     [ 500.000,  550.000) = 3
[info]     [ 550.000,  600.000) = 14
[info]     [ 600.000,  650.000) = 3
[info]     [ 650.000,  700.000) = 4
[info]     [ 700.000,  750.000) = 1
[info]     [ 750.000,  800.000) = 3
[info]     [ 800.000,  850.000) = 1
[info]     [ 850.000,  900.000) = 0
[info]     [ 900.000,  950.000) = 1
[info]   Percentiles, ms/op:
[info]       p(0.0000) =    537.693 ms/op
[info]      p(50.0000) =    568.977 ms/op
[info]      p(90.0000) =    793.142 ms/op
[info]      p(95.0000) =    853.890 ms/op
[info]      p(99.0000) =    917.850 ms/op
[info]      p(99.9000) =    917.850 ms/op
[info]      p(99.9900) =    917.850 ms/op
[info]      p(99.9990) =    917.850 ms/op
[info]      p(99.9999) =    917.850 ms/op
[info]     p(100.0000) =    917.850 ms/op
[info] # Run complete. Total time: 00:00:26
[info] REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
[info] why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
[info] experiments, perform baseline and negative tests that provide experimental control, make sure
[info] the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
[info] Do not assume the numbers tell you what you want them to tell.
[info] Benchmark      Mode  Cnt    Score    Error  Units
[info] GraalTest.run    ss   30  628.356 ± 67.159  ms/op
[success] Total time: 26 s, completed 2020/06/14 12:26:25

Résultats avec JVM standard

Les résultats sont décrits de manière bâclée, mais en résumé,

** Temps de préchauffage: 1075,011 ms / op ** ** Vitesse pure: 628,356 ms / op **

ms / op est une unité qui exprime le temps qu'il a fallu pour exécuter une fois la méthode cible. Comme le temps de préchauffage prend plus de temps que la vitesse pure, vous pouvez également voir qu'il se compile normalement après 10 000 échauffements.

Exécuter sur GraalVM

Cette fois, le coup de coeur, mesuré avec GraalVM! Tout d'abord, compilez.

sbt:jitCompiler> jmh:compile
[info] Compiling 3 Scala sources to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/classes ...
...
[info] Compiling 5 Java sources to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/classes ...
[success] Total time: 5 s, completed 2020/06/14 12:18:06

Exécuter.


sbt:jitCompiler> jmh:run
Processing 9 classes from /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/classes with "reflection" generator
Writing out Java source to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/src_managed/jmh and resources to /Users/kinsho/workspace/loginfrastructure/jitCompiler/target/scala-2.13/resource_managed/jmh
[info] running (fork) org.openjdk.jmh.Main
[info] # JMH version: 1.21
[info] # VM version: JDK 1.8.0_252, OpenJDK 64-Bit Server VM GraalVM CE 20.1.0, 25.252-b09-jvmci-20.1-b02
[info] # VM invoker: /Library/Java/JavaVirtualMachines/graalvm-ce-java8-20.1.0/Contents/Home/jre/bin/java
[info] # VM options: <none>
[info] # Warmup: 1 iterations, single-shot each, 10000 calls per op
[info] # Measurement: 30 iterations, single-shot each, 10000 calls per op
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread
[info] # Benchmark mode: Single shot invocation time
[info] # Benchmark: graal.GraalTest.run
[info] # Run progress: 0.00% complete, ETA 00:00:00
[info] # Fork: 1 of 1
[info] # Warmup Iteration   1: 1012.169 ms/op
[info] Iteration   1: 546.073 ms/op
[info] Iteration   2: 584.707 ms/op
[info] Iteration   3: 547.958 ms/op
[info] Iteration   4: 662.077 ms/op
[info] Iteration   5: 549.202 ms/op
[info] Iteration   6: 490.277 ms/op
[info] Iteration   7: 620.376 ms/op
[info] Iteration   8: 780.583 ms/op
[info] Iteration   9: 576.626 ms/op
[info] Iteration  10: 508.686 ms/op
[info] Iteration  11: 543.451 ms/op
[info] Iteration  12: 589.145 ms/op
[info] Iteration  13: 515.498 ms/op
[info] Iteration  14: 524.002 ms/op
[info] Iteration  15: 717.083 ms/op
[info] Iteration  16: 839.723 ms/op
[info] Iteration  17: 523.987 ms/op
[info] Iteration  18: 519.271 ms/op
[info] Iteration  19: 525.304 ms/op
[info] Iteration  20: 530.935 ms/op
[info] Iteration  21: 634.322 ms/op
[info] Iteration  22: 545.711 ms/op
[info] Iteration  23: 513.338 ms/op
[info] Iteration  24: 518.737 ms/op
[info] Iteration  25: 519.130 ms/op
[info] Iteration  26: 575.139 ms/op
[info] Iteration  27: 745.525 ms/op
[info] Iteration  28: 774.832 ms/op
[info] Iteration  29: 830.160 ms/op
[info] Iteration  30: 549.396 ms/op
[info] Result "graal.GraalTest.run":
[info]   N = 30
[info]   mean =    596.708 ±(99.9%) 68.925 ms/op
[info]   Histogram, ms/op:
[info]     [400.000, 450.000) = 0
[info]     [450.000, 500.000) = 1
[info]     [500.000, 550.000) = 16
[info]     [550.000, 600.000) = 4
[info]     [600.000, 650.000) = 2
[info]     [650.000, 700.000) = 1
[info]     [700.000, 750.000) = 2
[info]     [750.000, 800.000) = 2
[info]     [800.000, 850.000) = 2
[info]   Percentiles, ms/op:
[info]       p(0.0000) =    490.277 ms/op
[info]      p(50.0000) =    548.580 ms/op
[info]      p(90.0000) =    780.008 ms/op
[info]      p(95.0000) =    834.463 ms/op
[info]      p(99.0000) =    839.723 ms/op
[info]      p(99.9000) =    839.723 ms/op
[info]      p(99.9900) =    839.723 ms/op
[info]      p(99.9990) =    839.723 ms/op
[info]      p(99.9999) =    839.723 ms/op
[info]     p(100.0000) =    839.723 ms/op
[info] # Run complete. Total time: 00:00:25
[info] REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
[info] why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
[info] experiments, perform baseline and negative tests that provide experimental control, make sure
[info] the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
[info] Do not assume the numbers tell you what you want them to tell.
[info] Benchmark      Mode  Cnt    Score    Error  Units
[info] GraalTest.run    ss   30  596.708 ± 68.925  ms/op
[success] Total time: 26 s, completed 2020/06/14 12:22:50

Résultats avec GraalVm

Les résultats sont également décrits de manière bâclée cette fois, mais en résumé,

** Temps de préchauffage: 1012,169 ms / op ** ** Temps d'exécution pur: 596,708 ms / op **

Résultat global

À la suite de la mesure, il a été constaté que Graal était plus rapide. (Si cette méthode de mesure est correcte, il semble y avoir plus de points à considérer)

référence

Recommended Posts

J'ai essayé de mesurer et de comparer la vitesse de Graal VM avec JMH
J'ai essayé de comparer la technologie d'infrastructure des ingénieurs ces jours-ci avec la cuisine.
J'ai essayé d'augmenter la vitesse de traitement avec l'ingénierie spirituelle
J'ai essayé de résumer les bases de kotlin et java
J'ai essayé de résoudre le problème de la "sélection multi-étapes" avec Ruby
J'ai essayé de créer un environnement de serveur UML Plant avec Docker
J'ai essayé de vérifier le fonctionnement du serveur gRPC avec grpcurl
J'ai essayé de résumer les méthodes de Java String et StringBuilder
J'ai essayé d'exprimer les résultats avant et après de la classe Date avec une ligne droite numérique
J'ai essayé de résumer les points clés de la conception et du développement de gRPC
J'ai essayé de lire et de sortir CSV avec Outsystems
05. J'ai essayé de supprimer la source de Spring Boot
J'ai démarré MySQL 5.7 avec docker-compose et j'ai essayé de me connecter
J'ai essayé de réduire la capacité de Spring Boot
J'ai essayé de vérifier le fonctionnement de la requête http (Put) avec Talented API Tester
J'ai essayé d'étudier le mécanisme d'Emscripten en l'utilisant avec un solveur allemand
J'ai essayé de vérifier ceci et celui de Spring @ Transactional
J'ai essayé JAX-RS et pris note de la procédure
J'ai essayé de créer un environnement de WSL2 + Docker + VSCode
Assurez-vous de comparer le résultat Java compareTo avec 0
Janken de Sazae J'ai essayé de vérifier la valeur théorique et la valeur mesurée de la probabilité de la même main 5 fois consécutives avec Ruby
J'ai essayé d'interagir avec Java
J'ai essayé d'expliquer la méthode
[Pour les débutants Swift] J'ai essayé de résumer le cycle de mise en page désordonné de ViewController et View
Je veux revenir à l'écran précédent avec kotlin et java!
J'ai essayé de résoudre le problème de Google Tech Dev Guide
J'ai essayé de résumer les méthodes utilisées
J'ai essayé de démarrer avec Web Assembly
J'ai essayé d'implémenter le modèle Iterator
J'ai essayé de résumer l'API Stream
Je veux afficher des images avec REST Controller de Java et Spring!
[Ruby] Je souhaite extraire uniquement la valeur du hachage et uniquement la clé
J'ai essayé de résoudre le problème de la séquence Tribonacci en Ruby, avec récurrence.
Je veux passer l'argument d'Annotation et l'argument de la méthode d'appel à aspect
J'ai essayé d'utiliser pleinement le cœur du processeur avec Ruby
J'ai essayé de traduire la grammaire de R et Java [Mis à jour de temps en temps]
Après tout, je voulais prévisualiser le contenu de mysql avec Docker ...
J'ai essayé de comprendre le flux lors de l'analyse d'image avec Vision Framework et Core ML
J'ai essayé de vérifier AdoptOpenJDK 11 (11.0.2) avec l'image Docker
J'ai essayé de gérer la configuration des jambes de force avec Coggle
J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android
[Rails] J'ai essayé de faire passer la version de Rails de 5.0 à 5.2
J'ai essayé de gérer les informations de connexion avec JMX
J'ai essayé d'organiser la session en Rails
Ce que j'ai essayé quand je voulais obtenir tous les champs d'un haricot
J'ai essayé de lier grafana et postgres [docker-compose]
J'ai aussi essayé Web Assembly avec Nim et C
J'ai comparé les caractéristiques de Java et .NET
C # (base de l'encapsulation)
Je veux var_dump le contenu de l'intention
J'ai essayé de lier JavaFX et Spring Framework.
J'ai essayé de configurer tomcat pour exécuter le servlet.
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot