美文网首页
JMH idea Gradle helloworld-run-e

JMH idea Gradle helloworld-run-e

作者: 鹅鹅鹅_ | 来源:发表于2018-12-30 14:11 被阅读0次

    最近在琢磨Java性能优化,感触最深的一句话是,不要轻易优化,不要盲目自信的优化,一定要基于测试对比进行优化。比如对于一个可优化的小技巧,网上说的各种天花乱坠,也有可能两篇文章说的不一样,到底信那个?信自己的测试!所以我选择了学习JMH。

    JMH 是一个由 OpenJDK/Oracle 里面那群开发了 Java 编译器的大牛们所开发的 Micro Benchmark Framework 。何谓 Micro Benchmark 呢?简单地说就是在 method 层面上的 benchmark,精度可以精确到微秒级。可以看出 JMH 主要使用在当你已经找出了热点函数,而需要对热点函数进行进一步的优化时,就可以使用 JMH 对优化的效果进行定量的分析。
    JMH官方examples

    我用的是Idea,gradle,真的有点坑,所以写下这篇文章记录,抛砖引玉,避免别人再采坑。

    我只是想run一个最简单的example...

    • 可以download 我的git示例 JMH-Example

    • 目录结构


      目录结构
    • gradle.build

    group = 'jmh-example'
    version = '1.0'
    apply plugin: 'java'
    sourceCompatibility = 1.8
    
    repositories {
        jcenter()
        mavenCentral()
    }
    
    dependencies {
        compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
        compile group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.21'
        compile group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.21'
    }
    
    sourceSets {
        main {
            java.srcDirs = ['src']
        }
        test {
            java.srcDirs = ['test']
        }
    }
    
    • HelloBenchmark.java
    package main.java;
    import org.openjdk.jmh.annotations.*;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.RunnerException;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    
    import java.util.concurrent.TimeUnit;
    
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    @State(Scope.Thread) //Thread: 该状态为每个线程独享。
    public class HelloBenchmark {
        @Benchmark
        public int sleepAWhile() {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // ignore
            }
            return 0;
        }
    
        public static void main(String[] args) throws RunnerException {
            Options opt = new OptionsBuilder()
                    .include(HelloBenchmark.class.getSimpleName()) //benchmark 所在的类的名字,注意这里是使用正则表达式对所有类进行匹配的
                    .forks(1) //进行 fork 的次数。如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试
                    .warmupIterations(5) //预热的迭代次数
                    .measurementIterations(5) //实际测量的迭代次数
                    .build();
    
            new Runner(opt).run();
        }
    }
    
    Unable to find the resource: /META-INF/BenchmarkList
    
    Error:(3, 0) Unable to load class 'org.gradle.api.provider.Property'.
    Possible causes for this unexpected error include:<ul><li>Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)
    <a href="syncProject">Re-download dependencies and sync project (requires network)</a></li><li>The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.
    <a href="stopGradleDaemons">Stop Gradle build processes (requires restart)</a></li><li>Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.</li></ul>In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.
    

    如果你遇到了上述错误,看这篇文章就对了。其实根本不必安装任何插件。想要run起来只需要包含下面两个库就可以了。

    jmh-core
    jmh-generator-annprocess
    

    如果找不到/META-INF/BenchmarkList,原因是没有导入jmh-generator-annprocess。可以直接手动下载jmh-generator-annprocess就可以run起来了。


    image.png
    image.png
    • final solution
      真正的原因在于如果是以testCompile开头引入依赖的话,而运行的代码在main目录下而不是test目录,会造成main模块不会依赖jmh-generator-annprocess。这种情况下可以把testCompile改为compile即可。
    #把testCompile改为compile即可
    testCompile group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.21'
    
    • testCompile


      testCompile
    • compile


      compile
    • run output

    /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/lib/tools.jar:/Users/liuyihao/Documents/GitHub/JMH/out/production/classes:/Users/liuyihao/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.8.1/6505a72a097d9270f7a9e7bf42c4238283247755/commons-lang3-3.8.1.jar:/Users/liuyihao/.gradle/caches/modules-2/files-2.1/org.openjdk.jmh/jmh-core/1.21/442447101f63074c61063858033fbfde8a076873/jmh-core-1.21.jar:/Users/liuyihao/.gradle/caches/modules-2/files-2.1/org.openjdk.jmh/jmh-generator-annprocess/1.21/7aac374614a8a76cad16b91f1a4419d31a7dcda3/jmh-generator-annprocess-1.21.jar:/Users/liuyihao/.gradle/caches/modules-2/files-2.1/net.sf.jopt-simple/jopt-simple/4.6/306816fb57cf94f108a43c95731b08934dcae15c/jopt-simple-4.6.jar:/Users/liuyihao/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.2/ec2544ab27e110d2d431bdad7d538ed509b21e62/commons-math3-3.2.jar main.java.HelloBenchmark
    # JMH version: 1.21
    # VM version: JDK 1.8.0_151, Java HotSpot(TM) 64-Bit Server VM, 25.151-b12
    # VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/bin/java
    # VM options: -Dfile.encoding=UTF-8
    # Warmup: 5 iterations, 10 s each
    # Measurement: 5 iterations, 10 s each
    # Timeout: 10 min per iteration
    # Threads: 1 thread, will synchronize iterations
    # Benchmark mode: Average time, time/op
    # Benchmark: main.java.HelloBenchmark.sleepAWhile
    
    # Run progress: 0.00% complete, ETA 00:01:40
    # Fork: 1 of 1
    # Warmup Iteration   1: 503670.436 us/op
    # Warmup Iteration   2: 503833.837 us/op
    # Warmup Iteration   3: 503956.040 us/op
    # Warmup Iteration   4: 503632.164 us/op
    # Warmup Iteration   5: 503362.804 us/op
    Iteration   1: 503255.077 us/op
    Iteration   2: 504072.009 us/op
    Iteration   3: 503357.188 us/op
    Iteration   4: 503521.192 us/op
    Iteration   5: 503713.174 us/op
    
    
    Result "main.java.HelloBenchmark.sleepAWhile":
      503583.728 ±(99.9%) 1245.398 us/op [Average]
      (min, avg, max) = (503255.077, 503583.728, 504072.009), stdev = 323.426
      CI (99.9%): [502338.330, 504829.126] (assumes normal distribution)
    
    
    # Run complete. Total time: 00:01:42
    
    REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
    why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
    experiments, perform baseline and negative tests that provide experimental control, make sure
    the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
    Do not assume the numbers tell you what you want them to tell.
    
    Benchmark                   Mode  Cnt       Score      Error  Units
    HelloBenchmark.sleepAWhile  avgt    5  503583.728 ± 1245.398  us/op
    
    Process finished with exit code 0
    

    或者把源文件统一放在test目录下。

    • 重构。若重构后测试类名或者包名发生变化,需要删除编译目录重新编译。主要是删除BenchmarkList文件


      image.png

    相关文章

      网友评论

          本文标题:JMH idea Gradle helloworld-run-e

          本文链接:https://www.haomeiwen.com/subject/awtvlqtx.html