Skip to content

Instantly share code, notes, and snippets.

@YaSuenag
Last active May 19, 2017 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YaSuenag/a4bea7922bd0790550d4 to your computer and use it in GitHub Desktop.
Save YaSuenag/a4bea7922bd0790550d4 to your computer and use it in GitHub Desktop.
JVMCIを使ってみよう(メソッドプロファイル取得編)

とりあえず、JVMCI経由でメソッドプロファイル情報を取得してみます。

方針

  • プロファイルを取得したいクラスを予め決めておき、シャットダウンフック実行時に一気にダンプします。
  • JVMCIではメソッド単位でコントロール可能ですが、とりあえずクラス内定義メソッド全部をダンプするようにします。

JVMCI取得部

/*
 * Copyright (C) 2015 Yasumasa Suenaga
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
import java.util.*;
import jdk.vm.ci.runtime.*;
import jdk.vm.ci.hotspot.*;


/* Please run with -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI */
public class JVMCIWatch{

  private final List<Class<?>> classList;

  public JVMCIWatch(List<Class<?>> classList){
    this.classList = classList;
    Runtime.getRuntime().addShutdownHook(new Thread(() -> dumpProfiles()));

    System.out.println("Watch targets:");
    classList.stream()
             .forEach(c -> System.out.println("  " + c.toString()));
  }

  public void dumpProfiles(){
    JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend();
    HotSpotMetaAccessProvider metaAccess =
                           (HotSpotMetaAccessProvider)backend.getMetaAccess();

    System.out.println("Profile data:");
    classList.stream()
             .flatMap(c -> Arrays.stream(c.getMethods()))
             .peek(m -> System.out.print(m.toString() + ": "))
             .map(metaAccess::lookupJavaMethod)
             .map(m -> m.getProfilingInfo(true, true))
             .forEach(System.out::println);
  }

}

テストケース

/*
 * Copyright (C) 2015 Yasumasa Suenaga
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
import java.util.*;


public class JVMCITest{

  public static void runLoop(int max){
    int result = 0;

    for(int i = 1; i <= max; i++){
      result += i;
    }

    System.out.println(result);
  }

  public static void main(String[] args) throws Exception{
    List<Class<?>> classList = new ArrayList<>();
    classList.add(JVMCITest.class);
    classList.add(JVMCIWatch.class);

    new JVMCIWatch(classList);

    runLoop(1000000);
  }

}

コンパイル&実行

実行時に必ず -XX:+UnlockExperimentalVMOptions-XX:+EnableJVMCI の2つを付与してください。

$ /usr/local/jdk-9/bin/javac *.java
$ /usr/local/jdk-9/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI JVMCITest
Watch targets:
  class JVMCITest
  class JVMCIWatch
1784293664
Profile data:
public static void JVMCITest.runLoop(int): HotSpotProfilingInfo<exceptionSeen@0: FALSE; exceptionSeen@1: FALSE; exceptionSeen@2: FALSE; exceptionSeen@3: FALSE; exceptionSeen@4: FALSE; exceptionSeen@5: FALSE; executionCount@6: 600064; branchProbability@6: 0.000002; exceptionSeen@6: FALSE; exceptionSeen@7: FALSE; exceptionSeen@8: FALSE; exceptionSeen@9: FALSE; exceptionSeen@10: FALSE; exceptionSeen@11: FALSE; exceptionSeen@12: FALSE; exceptionSeen@13: FALSE; exceptionSeen@14: FALSE; exceptionSeen@15: FALSE; executionCount@16: 600063; branchProbability@16: 1.000000; exceptionSeen@16: FALSE; exceptionSeen@17: FALSE; exceptionSeen@18: FALSE; exceptionSeen@19: FALSE; exceptionSeen@20: FALSE; exceptionSeen@21: FALSE; exceptionSeen@22: FALSE; executionCount@23: 1; exceptionSeen@23: FALSE; nullSeen@23: FALSE; types@23: 1.000000 (HotSpotType<Ljava/io/PrintStream;, resolved>);  <no other types>; exceptionSeen@24: FALSE; exceptionSeen@25: FALSE; exceptionSeen@26: FALSE>
public static void JVMCITest.main(java.lang.String[]) throws java.lang.Exception: DefaultProfilingInfo<>
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException: DefaultProfilingInfo<>
public final void java.lang.Object.wait() throws java.lang.InterruptedException: DefaultProfilingInfo<>
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException: DefaultProfilingInfo<>
public boolean java.lang.Object.equals(java.lang.Object): DefaultProfilingInfo<>
public java.lang.String java.lang.Object.toString(): DefaultProfilingInfo<>
public native int java.lang.Object.hashCode(): DefaultProfilingInfo<>
public final native java.lang.Class java.lang.Object.getClass(): DefaultProfilingInfo<>
public final native void java.lang.Object.notify(): DefaultProfilingInfo<>
public final native void java.lang.Object.notifyAll(): DefaultProfilingInfo<>
public void JVMCIWatch.dumpProfiles(): DefaultProfilingInfo<>
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException: DefaultProfilingInfo<>
public final void java.lang.Object.wait() throws java.lang.InterruptedException: DefaultProfilingInfo<>
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException: DefaultProfilingInfo<>
public boolean java.lang.Object.equals(java.lang.Object): DefaultProfilingInfo<>
public java.lang.String java.lang.Object.toString(): DefaultProfilingInfo<>
public native int java.lang.Object.hashCode(): DefaultProfilingInfo<>
public final native java.lang.Class java.lang.Object.getClass(): DefaultProfilingInfo<>
public final native void java.lang.Object.notify(): DefaultProfilingInfo<>
public final native void java.lang.Object.notifyAll(): DefaultProfilingInfo<>

インタプリタモードでは DefaultProfilingInfo 、JITコンパイル済みコードは HotSpotProfilingInfo のインスタンスとして表示されるようです(あまり深追いしていません)。

@YaSuenag
Copy link
Author

深追いした結果を Java Day Tokyo 2017のD1-C1で発表しました。資料サンプルコードも公開しているので、ぜひご覧ください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment