如果您想对代码进行基准测试,Java Microbenchmark Harness 是首选工具。在我们的示例中,我们将使用refill-rate-limiter项目
由于 refill-rate-limiter 使用Gradle,我们将使用以下gradle插件:
plugins { ... id "me.champeau.gradle.jmh" version "0.5.3" ...
|
我们将基准放在 jmh/java/io/github/resilience4j/ratelimiter 文件夹中。
我们的基准应该是这样的。
package io.github.resilience4j.ratelimiter; import io.github.resilience4j.ratelimiter.internal.RefillRateLimiter; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.profile.GCProfiler; 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.time.Duration; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.All) public class RateLimiterBenchmark { private static final int FORK_COUNT = 2; private static final int WARMUP_COUNT = 10; private static final int ITERATION_COUNT = 10; private static final int THREAD_COUNT = 2; private RefillRateLimiter refillRateLimiter; private Supplier<String> refillGuardedSupplier; public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .addProfiler(GCProfiler.class) .build(); new Runner(options).run(); } @Setup public void setUp() { RefillRateLimiterConfig refillRateLimiterConfig = RefillRateLimiterConfig.custom() .limitForPeriod(1) .limitRefreshPeriod(Duration.ofNanos(1)) .timeoutDuration(Duration.ofSeconds(5)) .build(); refillRateLimiter = new RefillRateLimiter("refillBased", refillRateLimiterConfig); Supplier<String> stringSupplier = () -> { Blackhole.consumeCPU(1); return "Hello Benchmark"; }; refillGuardedSupplier = RateLimiter.decorateSupplier(refillRateLimiter, stringSupplier); } @Benchmark @Threads(value = THREAD_COUNT) @Warmup(iterations = WARMUP_COUNT) @Fork(value = FORK_COUNT) @Measurement(iterations = ITERATION_COUNT) public String refillPermission() { return refillGuardedSupplier.get(); } }
|
通过使用基准范围,基准范围上使用的所有线程将共享同一对象。我们这样做是因为我们想要测试 refill-rate-limiter 在多线程场景中的执行情况。
@State(Scope.Benchmark)
我们希望以微秒为单位报告结果,因此我们将使用 OutputTimeUnit。
@OutputTimeUnit(TimeUnit.MICROSECONDS)
在 JMH 上,我们有各种基准模式,具体取决于我们想要测量的内容。
- 吞吐量是指我们想要测量单位时间的操作数量。
- AverageTime 当我们想要测量每个操作的平均时间时。
- SampleTime 当我们想要对每个操作的时间进行采样时,包括最小、最大时间,而不仅仅是平均值。
- SingleShotTime:当我们想要测量单个操作的时间时。当我们想要确定操作在冷启动时如何执行时,这会有所帮助。
我们还可以选择测量上述所有内容。
@BenchmarkMode(Mode.All)
在类级别配置的那些选项将应用于我们将添加的基准方法。
我们还检查一下基准测试将如何运行
我们将使用 Threads 注释指定线程数。
@Threads(value = THREAD_COUNT)
此外,我们希望在运行实际基准测试之前进行热身。这样我们的代码将被初始化,在线优化将发生,并且我们的运行时将在运行基准测试之前适应条件。
@Warmup(iterations = WARMUP_COUNT)
使用 Fork,我们将指示基准测试将运行多少次。
@Fork(value = FORK_COUNT)
然后我们需要指定我们想要测量的迭代次数/
@Measurement(iterations = ITERATION_COUNT)
我们可以通过使用来开始我们的测试
gradle jmh
结果将保存在文件中。