一、基准测试
-
基准测试是什么
-
基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。
-
例如,对计算机CPU进行浮点运算、数据访问的带宽和延迟等指标的基准测试,可以使用户清楚地了解每一款CPU的运算性能及作业吞吐能力是否满足应用程序的要求
-
再如对数据库管理系统的ACID(Atomicity, Consistency, Isolation, Durability, 原子性、一致性、独立性和持久性)、查询时间和联机事务处理能力等方面的性能指标进行基准测试,也有助于使用者挑选最符合自己需求的数据库系统
-
-
通过基准测试,我们可以了解某个软件在给定环境下的性能表现,对使用者而言可以用作选型的参考,对开发者而言可以作为后续改进的基本参照。
二、JMH
-
JMH是什么
三、入门
-
因为 JMH 是 JDK9 之后才自带的,如果是 JDK9 之前的版本需要加入如下依赖
<dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.32</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.32</version> </dependency>
3.1 第一个例子:Hello JMH
import org.openjdk.jmh.annotations.Benchmark; 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; public class Example_01_HelloJMH { @Benchmark public String sayHello() { return "HELLO JMH!"; } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(Example_01_HelloJMH.class.getSimpleName()) .forks(1) .build(); new Runner(options).run(); } }
3.2 运行结果
# JMH version: 1.32 # VM version: JDK 1.8.0_241, Java HotSpot(TM) 64-Bit Server VM, 25.241-b07 # VM invoker: G:\Java\jdk1.8.0_241\jre\bin\java.exe # VM options: -javaagent:G:\JetBrains\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=56180:G:\JetBrains\IntelliJ IDEA 2020.2.3\bin -Dfile.encoding=UTF-8 # Blackhole mode: full + dont-inline hint # 预热配置 # 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: Throughput, ops/time # 当前测试的方法 # Benchmark: com.ziroom.test.Example_01_HelloJMH.sayHello # 运行过程的输出 # Run progress: 0.00% complete, ETA 00:01:40 # Fork: 1 of 1 # Warmup Iteration 1: 2924740803.993 ops/s # Warmup Iteration 2: 2916472711.387 ops/s # Warmup Iteration 3: 3024204715.897 ops/s # Warmup Iteration 4: 3051723946.668 ops/s # Warmup Iteration 5: 2924014544.301 ops/s Iteration 1: 2909665054.710 ops/s Iteration 2: 2989675862.826 ops/s Iteration 3: 2965046292.629 ops/s Iteration 4: 3020263765.220 ops/s Iteration 5: 2929485177.735 ops/s # 当前方法测试结束的报告 Result "com.ziroom.test.Example_01_HelloJMH.sayHello": 2962827230.624 ±(99.9%) 171803440.922 ops/s [Average] (min, avg, max) = (2909665054.710, 2962827230.624, 3020263765.220), stdev = 44616808.022 CI (99.9%): [2791023789.702, 3134630671.547] (assumes normal distribution) # Run complete. Total time: 00:01:41 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跑完后的最终报告 Benchmark Mode Cnt Score Error Units Example_01_HelloJMH.sayHello thrpt 5 2962827230.624 ± 171803440.922 ops/s
3.3 使用 JMH 测试 Spring/SpringBoot
import com.spadesk.springbootjmhtest.controller.TestController; 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 org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class SpringBootBenchMark { public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(SpringBootBenchMark.class.getSimpleName()) .warmupItera