概览
Gravitino JMH 目录包含一套基于 JMH 的微基准测试(Microbenchmark)套件,专门用于评估 Gravitino 中核心子系统的性能特征,如:实体缓存(Entity Cache)、元数据解析逻辑以及并发控制机制等。
执行方式
使用如下命令运行 JMH 测试:
./gradlew :core:jmh
测试完成后,结果将保存于:build/reports/jmh
目录中。
示例报告格式
Benchmark (totalCnt) Mode Cnt Score Error Units
EntityCacheGetBenchmark.benchmarkGet 100 thrpt 10 17906401.139 ± 905521.957 ops/s
EntityCachePutBenchmark.benchmarkPut 1000 avgt 10 0.002 ± 0.001 s/op
- Score:每秒操作数或每次调用耗时;
- Error:误差范围(通常为 99.9% 置信区间),即结果可信区间为 Score ± Error;
例如:
Score: 19008727.28 ops/s
Error: ± 1172892.70 ops/s
=> 实际性能大概率处于 17,835,834 ~ 20,181,620 ops/s 之间
误差越小,说明测试结果越稳定可靠。
什么是 JMH?
JMH(Java Microbenchmark Harness)是 OpenJDK 团队专为 Java 微基准测试开发的框架,主要用于精确测量方法调用、缓存访问、对象分配等细粒度操作的性能。
相较于传统测试方式,JMH 能处理如下影响因素:
- JIT 编译和 JVM 热身(warm-up)
- 死代码消除(Dead Code Elimination)
- 逃逸分析(Escape Analysis)
- 线程争用和伪共享(False Sharing)
JMH 提供基于注解的 API,并自动处理多次迭代、预热、JVM fork 和统计报告,已被广泛应用于 JDK、Spring、Netty、Lucene 等高性能项目。
示例基准代码
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
public class StringConnectTest {
@Param({"10", "50", "100"})
private int length;
@Benchmark
public void testStringAdd(Blackhole blackhole) {
String a = "";
for (int i = 0; i < length; i++) {
a += i;
}
blackhole.consume(a);
}
@Benchmark
public void testStringBuilderAdd(Blackhole blackhole) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(i);
}
blackhole.consume(sb.toString());
}
}
常用注解说明
注解 | 说明 |
---|---|
@Benchmark |
声明基准方法,JMH 会多次调用并测量其性能 |
@BenchmarkMode |
设置测量模式,如吞吐量(Throughput)、平均时间(AverageTime) |
@OutputTimeUnit |
设置时间单位,如秒(SECONDS)、毫秒、纳秒等 |
@State |
设置对象共享粒度,常用为 Scope.Thread (每线程独立) |
@Param |
参数化测试,生成多组输入用例 |
BenchmarkMode 模式说明
模式 | 含义 |
---|---|
Throughput |
吞吐量,每秒完成操作数 |
AverageTime |
每次操作的平均耗时 |
SampleTime |
对多个样本测量操作耗时,展示分布 |
SingleShotTime |
单次调用耗时,适合冷启动分析 |
All |
执行所有模式 |
在 Gravitino 中使用 JMH
Gravitino 使用 jmh-gradle-plugin 集成 JMH 到 Gradle 构建中。
插件配置
在 build.gradle
中添加:
plugins {
id "me.champeau.jmh" version "0.7.3"
}
注意:0.6.0 之前版本的插件 ID 为
me.champeau.gradle.jmh
目录结构
基准测试文件需放置于以下目录:
src/jmh/java # Java 测试代码
src/jmh/resources # 资源文件(可选)
依赖引入
若基准测试依赖第三方库,如 commons-io,可在 dependencies
中添加:
dependencies {
jmh 'commons-io:commons-io:2.7'
}
要指定 JMH 版本:
dependencies {
jmh 'org.openjdk.jmh:jmh-core:1.37'
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
}
JMH 测试任务
任务名 | 说明 |
---|---|
jmhClasses |
编译测试源代码 |
jmhRunBytecodeGenerator |
运行字节码生成器 |
jmhCompileGeneratedClasses |
编译生成代码 |
jmhJar |
打包成可运行 JMH jar |
jmh |
执行所有基准测试(主任务) |
执行命令:
./gradlew :core:jmh
常用配置项
jmh {
includes = ['.*Benchmark'] // 正则匹配要执行的测试类
iterations = 10 // 测量阶段迭代次数
warmupIterations = 5 // 预热阶段迭代次数
fork = 1 // JVM 启动次数(独立运行)
threads = 4 // 工作线程数
resultFormat = 'CSV' // 报告格式(CSV、JSON、TEXT等)
resultsFile = file("$buildDir/reports/jmh/results.csv")
includeTests = true // 是否包含 test 目录中的类
duplicateClassesStrategy = DuplicatesStrategy.FAIL
}
更多映射与命令行选项见:配置选项映射表
JMH 补充说明
为什么需要 Warm-up(预热)?
由于 JVM 存在 JIT 编译机制,频繁调用的方法可能会被编译为本地代码。预热阶段可确保测试结果更贴近生产环境下的真实性能。
可视化工具
支持导入 JSON/CSV 报告生成图表。
IntelliJ 插件支持
安装 JMH 插件后,可像运行 JUnit 一样运行基准测试:
- 自动生成带
@Benchmark
的方法模板 - 单独运行方法或类中的所有测试
- 插件路径:
File → Settings → Plugins → 搜索 JMH