Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

GraalVMを使ってみる

前書き

GraalVMのパフォーマンス、しいては、GraalをJITコンパイラとして利用した際のパフォーマンスにフォーカスした記事なので、GraalVMの特徴の一つであるnative imageや、multiple languagesなどに関しては、この記事では触れていない。

環境

  • macOS Mojava 10.14.4
  • Scala 2.13.1
  • sbt 1.3.8
  • GraalVM 20.1

GraalVMとは

Javaで書かれた最新のJITコンパイラ、Graalを搭載したVMである。
GraalVM公式ドキュメントによると、Graalには以下の特徴がある。

Graal自体がjavaで実装されているので、標準のJITコンパイラではできなかった部分的なエスケープ分析などの強力な最適化により、Javaプログラムを大幅に高速化できる

実際にどのくらい速くなるのかは後述している。

ちなみに、VM変更するのは面倒であれば、以下のオプションをつけることで、JITコンパイラだけGraalに変えることもできるらしい。
しかし、参考によるとJDK10以降でしか使えないので注意。

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

特徴は以下の資料にまとめている
https://drive.google.com/file/d/1UKw_7dM-2SLQhnrM5cq4hemL9yqDxhPI/view?usp=sharing

GraalVMのアーキテクチャ

以下のようなアーキテクチャになっている。
標準JVMと比べて、C2部分がGraalコンパイラに置き換わっている。
GraalとJVMCIの部分が、Javaで実装されている。

Graal.png

JVMCI

Javaで実装されたコンパイラを動的コンパイラとしてJVMで利用できるようにしたもの。

実際に使ってみる

インストール

公式ドキュメントに書いている通りにする。
macOSの場合は、ここ

OpenJDKの標準VMとGraalVMで速度比較してみる

より詳細な速度比較は、こちらの記事に書いている。

275MbのGraalTest.txt に含まれている単語の種類からトップ10を吐き出すプログラムを実行する。


$ ll
total 65368
-rw-r--r--  1 kinsho  staff   202B  5 31 14:04 FibTest.scala
-rw-r--r--  1 kinsho  staff   1.9K  5 31 17:13 GraalTest.scala
-rw-r--r--  1 kinsho  staff   275M  5 31 16:54 GraalTest.txt
drwxr-xr-x  4 kinsho  staff   128B  5 31 14:28 project
drwxr-xr-x  5 kinsho  staff   160B  5 31 14:35 target

上述でインストールした、GraalVMをVMとして利用。

$ java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 25.252-b09-jvmci-20.1-b02, mixed mode)

以下、実行プログラム

GraalTest.scala
import java.io.File

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

object GraalTest extends App {

  val fileName: String = "GraalTest.txt"
  val encode: String = "UTF-8"

  val source: BufferedSource = scala.io.Source.fromFile(fileName, encode)
  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)

  def createMap(wordList: List[String]): Map[String, Long] = {
    @tailrec
    def loop(list: List[String], acc: Map[String, Long]): Map[String, Long] = {
      wordList 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)
            }
          }
        }
      }
    }
    loop(wordList, Map.empty[String, Long])
  }
}

結果

OpenJDKの標準VMでは!?

比較のために、OpenJDKの標準JITコンパイラを使ってプログラムを実行してみる。
-XX:-UseJVMCICompilerを指定すると、OpenJDKの標準JITコンパイラを利用できる。

.jvmopts
-XX:-UseJVMCICompiler
-Xmx8G
実行
$ /usr/bin/time sbt run GraalTest.scala

すると、以下のような結果が得られる。

JVM結果
[info] running GraalTest
List((the,3297996), (and,2198664), (of,2198664), (you,1648998), (a,1648998), (in,1648998), (about,1099332), (always,1099332), (with,1099332), (how,1099332))
[success] Total time: 64 s (01:04), completed 2020/06/04 0:38:37
       85.31 real       479.11 user         8.89 sys

GraalVMでは!?

上記のプログラムをGraalVM上で実行してみる。

.jvmopts
-Xmx8G
実行
$ /usr/bin/time sbt run GraalTest.scala

すると、以下のような結果が得られる。

GraalVM結果
[info] running GraalTest
List((the,3297996), (and,2198664), (of,2198664), (you,1648998), (a,1648998), (in,1648998), (about,1099332), (always,1099332), (with,1099332), (how,1099332))
[success] Total time: 54 s, completed 2020/06/04 0:40:02
       75.29 real       333.95 user         9.23 sys

GraalVMを使うことで、10sも早くなっていることがわかる。
これは、だいぶ早くなっている!!!!!

↓パフォーマンス測定で使ったコード達
https://github.com/kinshotomoya/loginfrastructure/tree/master/jitCompiler

まとめ

現状のJITコンパイラの代わりにGraalを利用するのは、使えるなら使うべき。

次回は、GraalVMのもう一つの特徴である、native-imageに関してまとめる。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
9
Help us understand the problem. What are the problem?