JMH(基准测试)
JMH只适合细粒度的方法测试
- maven依赖
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.21</version>
</dependency>
- 基本代码
package jmhTest;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.profile.StackProfiler;
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;
import java.util.concurrent.atomic.AtomicInteger;
//基准测试类型,tps,avg等
@BenchmarkMode({Mode.Throughput})
//基准测试结果的时间类型
@OutputTimeUnit(TimeUnit.SECONDS)
//预热的迭代次数
@Warmup(iterations = 2,time = 2)
//几个线程
@Threads(2)
//该状态为变量是每个线程独享
@State(Scope.Thread)
//度量:iterations进行测试的轮次,time每轮进行的时长,timeUnit时长单位,batchSize批次数量(batchSize结合SingleShotTime)
@Measurement(iterations = 2,time = 2)
//几个jvm虚拟机 防止环境干扰(JVM因为使用了profile-guided optimization而“臭名昭著”,这对于微基准测试来说十分不友好,因为不同测试方法的profile混杂在一起,“互相伤害”彼此的测试结果)
@Fork(2)
public class JmhTest3 {
public AtomicInteger atomicInteger = new AtomicInteger();
//初始化操作
@Setup
public void init(){
atomicInteger.set(0);
}
@Benchmark
public void test() throws Exception{
Thread.sleep(100);
atomicInteger.incrementAndGet();
}
//销毁操作
@TearDown
public void destory(){
System.out.println("==========");
System.out.println(atomicInteger.get());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JmhTest3.class.getSimpleName())
//addProfiler可以输出对应的profile信息比如下
//jmhTest.JmhTest3.test:·gc.alloc.rate thrpt 4 0.603 ± 0.145 MB/sec
//jmhTest.JmhTest3.test:·gc.alloc.rate.norm thrpt 4 0.003 ± 0.001 B/op
.addProfiler(StackProfiler.class)
.addProfiler(GCProfiler.class)
.build();
new Runner(opt).run();
}
}
- 其他注解
@Param
@CompilerControl //解释器的行为(方法内联\方法不内联\解释执行)
@Group //方法注解,可以把多个benchmark 定义为同一个group,则它们会被同时执行,譬如用来模拟生产者-消费者读写速度不一致情况下的表现
//todo
- 注意事项
死码消除
常量折叠与常量传播
不要Benchmark代码里面写循环
使用 Fork 隔离多个测试方法
方法内联
伪共享与缓存行
分支预测
多线程测试(电源管理\操作系统调度和分时调用模型)
JMH测试陷阱
JAVA 拾遗 — CPU Cache 与缓存行


