4. 报告结果
输出结果如下,
最后的结果:
Benchmark Mode Cnt Score Error Units LinkedListIterationBenchMark.forEachIterate thrpt 2 1192.380 ops/s LinkedListIterationBenchMark.forIndexIterate thrpt 2 206.866 ops/s
整个过程:
> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能 > > * 项目地址:<https://gitee.com/zhijiantianya/yudao-cloud> > * 视频教程:<https://doc.iocoder.cn/video/> # Detecting actual CPU count: 12 detected # JMH version: 1.21 # VM version: JDK 1.8.0_131, Java HotSpot(TM) 64-Bit Server VM, 25.131-b11 # VM invoker: C:\Program Files\Java\jdk1.8.0_131\jre\bin\java.exe # VM options: -javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\lib\idea_rt.jar=65175:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\bin -Dfile.encoding=UTF-8 # Warmup: 2 iterations, 10 s each # Measurement: 2 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 12 threads, will synchronize iterations # Benchmark mode: Throughput, ops/time # Benchmark: org.sample.jmh.LinkedListIterationBenchMark.forEachIterate # Run progress: 0.00% complete, ETA 00:01:20 # Fork: 1 of 1 # Warmup Iteration 1: 1189.267 ops/s # Warmup Iteration 2: 1197.321 ops/s Iteration 1: 1193.062 ops/s Iteration 2: 1191.698 ops/s Result "org.sample.jmh.LinkedListIterationBenchMark.forEachIterate": 1192.380 ops/s # JMH version: 1.21 # VM version: JDK 1.8.0_131, Java HotSpot(TM) 64-Bit Server VM, 25.131-b11 # VM invoker: C:\Program Files\Java\jdk1.8.0_131\jre\bin\java.exe # VM options: -javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\lib\idea_rt.jar=65175:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\bin -Dfile.encoding=UTF-8 # Warmup: 2 iterations, 10 s each # Measurement: 2 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 12 threads, will synchronize iterations # Benchmark mode: Throughput, ops/time # Benchmark: org.sample.jmh.LinkedListIterationBenchMark.forIndexIterate # Run progress: 50.00% complete, ETA 00:00:40 # Fork: 1 of 1 # Warmup Iteration 1: 205.676 ops/s # Warmup Iteration 2: 206.512 ops/s Iteration 1: 206.542 ops/s Iteration 2: 207.189 ops/s Result "org.sample.jmh.LinkedListIterationBenchMark.forIndexIterate": 206.866 ops/s # Run complete. Total time: 00:01:21 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 LinkedListIterationBenchMark.forEachIterate thrpt 2 1192.380 ops/s LinkedListIterationBenchMark.forIndexIterate thrpt 2 206.866 ops/s
注解介绍
下面我们来详细介绍一下相关的注解。
@BenchmarkMode
微基准测试类型。JMH 提供了以下几种类型进行支持:
类型 | 描述 |
Throughput | 每段时间执行的次数,一般是秒 |
AverageTime | 平均时间,每次操作的平均耗时 |
SampleTime | 在测试中,随机进行采样执行的时间 |
SingleShotTime | 在每次执行中计算耗时 |
All | 所有模式 |
可以注释在方法级别,也可以注释在类级别。
@BenchmarkMode(Mode.All) public class LinkedListIterationBenchMark { ... } @Benchmark @BenchmarkMode({Mode.Throughput, Mode.SingleShotTime}) public void m() { ... }
@Warmup
这个单词的意思就是预热,iterations = 3
就是指预热轮数。
@Benchmark @BenchmarkMode({Mode.Throughput, Mode.SingleShotTime}) @Warmup(iterations = 3) public void m() { ... }
@Measurement
正式度量计算的轮数。
iterations
进行测试的轮次time
每轮进行的时长timeUnit
时长单位
@Benchmark @BenchmarkMode({Mode.Throughput, Mode.SingleShotTime}) @Measurement(iterations = 3) public void m() { ... }
@Threads
每个进程中的测试线程。
@Threads(Threads.MAX) public class LinkedListIterationBenchMark { ... }
@Fork
进行 fork 的次数。如果 fork 数是3的话,则 JMH 会 fork 出3个进程来进行测试。
@Benchmark @BenchmarkMode({Mode.Throughput, Mode.SingleShotTime}) @Fork(value = 3) public void m() { ... }
@OutputTimeUnit
基准测试结果的时间类型。一般选择秒、毫秒、微秒。
@OutputTimeUnit(TimeUnit.SECONDS) public class LinkedListIterationBenchMark { ... }
@Benchmark
方法级注解,表示该方法是需要进行 benchmark 的对象,用法和 JUnit 的 @Test
类似。
@Param
属性级注解,@Param
可以用来指定某项参数的多种情况。特别适合用来测试一个函数在不同的参数输入的情况下的性能。
@Setup
方法级注解,这个注解的作用就是我们需要在测试之前进行一些准备工作 ,比如对一些数据的初始化之类的。
@TearDown
方法级注解,这个注解的作用就是我们需要在测试之后进行一些结束工作 ,比如关闭线程池,数据库连接等的,主要用于资源的回收等。
@State
当使用@Setup
参数的时候,必须在类上加这个参数,不然会提示无法运行。
就比如我上面的例子中,就必须设置state
。
State
用于声明某个类是一个“状态”,然后接受一个 Scope 参数用来表示该状态的共享范围。因为很多 benchmark 会需要一些表示状态的类,JMH 允许你把这些类以依赖注入的方式注入到 benchmark 函数里。Scope 主要分为三种。
- Thread: 该状态为每个线程独享。
- Group: 该状态为同一个组里面所有线程共享。
- Benchmark: 该状态在所有线程间共享。
启动方法
在启动方法中,可以直接指定上述说到的一些参数,并且能将测试结果输出到指定文件中,
/** * 仅限于IDE中运行 * 命令行模式 则是 build 然后 java -jar 启动 * * 1. 这是benchmark 启动的入口 * 2. 这里同时还完成了JMH测试的一些配置工作 * 3. 默认场景下,JMH会去找寻标注了@Benchmark的方法,可以通过include和exclude两个方法来完成包含以及排除的语义 */ public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() // 包含语义 // 可以用方法名,也可以用XXX.class.getSimpleName() .include("Helloworld") // 排除语义 .exclude("Pref") // 预热10轮 .warmupIterations(10) // 代表正式计量测试做10轮, // 而每次都是先执行完预热再执行正式计量, // 内容都是调用标注了@Benchmark的代码。 .measurementIterations(10) // forks(3)指的是做3轮测试, // 因为一次测试无法有效的代表结果, // 所以通过3轮测试较为全面的测试, // 而每一轮都是先预热,再正式计量。 .forks(3) .output("E:/Benchmark.log") .build(); new Runner(opt).run(); }
结语
基于JMH可以对很多工具和框架进行测试,比如日志框架性能对比、BeanCopy性能对比 等,更多的example可以参考官方给出的JMH samples(https://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/)