在空运行模式下运行 JMH

问题描述 投票:0回答:1

我正在修复 kotlinx.benchmark 中的一个错误,它包装了 JMH。开发速度要慢得多,因为测试实际上运行了基准测试,这对于我正在做的事情来说并不重要。我只需要验证 JMH 是否加载选项并正确选择基准测试,但实际上我并不需要 JMH 来运行和生成基准测试。

理想的方法是强制 JMH 在空运行模式下运行,即加载所有基准测试,但实际上并不运行它们。对于每个基准测试,它可能会返回假结果,甚至“0ms”结果。这样的事情可能吗?

运行JMH

以下是 kotlinx.benchmark 目前运行 JMH 的方式。

kotlinx.benchmark 通过 JvmBenchmarkRunner.kt

.
中的 org.openjdk.jmh.runner.Runner

类调用 JMH。

JvmBenchmarkRunner
可能比看起来更复杂,但其核心只是构建 JMH Options,然后运行它们,如下所示:

import org.openjdk.jmh.annotations.Mode
import org.openjdk.jmh.results.format.ResultFormatType
import org.openjdk.jmh.runner.Runner
import org.openjdk.jmh.runner.options.OptionsBuilder

fun main() {
  val options = OptionsBuilder()
    .warmupForks(3)
    .forks(2)
    .mode(Mode.Throughput)
    .resultFormat(ResultFormatType.TEXT)
    // (more options)
    .build()
  
  val runner = Runner(options)
  runner.run()
}

我使用 Kotlin/JVM 进行编码,但如果在 Java 中使用 JMH,这种情况也适用。

潜在的解决方案

  • 也许有一种方法可以注入一个类来覆盖现有的 JMH 类,这样测试就永远不会启动?
  • JMH如何自我测试?是否存在禁用基准测试执行的内部“集成测试模式”?也许有一个系统属性会禁用实际测试的执行?

虽然可以将时间设置得非常低,例如1ms,以便测试(几乎)立即运行,这是不希望的,因为它会阻止测试是否将正确的参数传递给 JMH。

java kotlin testing jvm jmh
1个回答
0
投票

要在加载基准但不实际执行的空运行模式下运行 JMH,您可以通过自定义

Benchmark
实现来自定义 JMH 的行为来实现这一点。虽然 JMH 不提供开箱即用的内置试运行模式,但您可以使用以下方法解决此限制:

方法:自定义基准运行程序

  • 创建自定义跑步者: 您可以创建 org.openjdk.jmh.runner.Runner 的自定义实现来覆盖运行基准测试的行为。这个自定义运行器将简单地模拟执行过程,而不是执行基准测试。

  • 覆盖基准执行: 您需要重写负责运行基准测试的方法,以便它跳过实际执行但仍然处理基准测试选项。

以下是如何为此目的设置自定义运行器的示例:

自定义运行器实现:

import org.openjdk.jmh.runner.Runner
import org.openjdk.jmh.runner.options.Options
import org.openjdk.jmh.runner.options.OptionsBuilder
import org.openjdk.jmh.runner.options.TimeValue
import org.openjdk.jmh.results.format.ResultFormatType
import org.openjdk.jmh.results.format.ResultFormat
import org.openjdk.jmh.runner.BenchmarkClassLoader
import org.openjdk.jmh.runner.BenchmarkList
import org.openjdk.jmh.runner.options.TimeValue
import java.util.concurrent.TimeUnit

class DryRunRunner(options: Options) : Runner(options) {
    override fun run() {
        println("Dry-run mode: Benchmarks loaded but not executed.")

        // Simulate loading benchmarks and printing them
        val benchmarks = BenchmarkList(options.benchmarks)
        benchmarks.forEach {
            println("Benchmark: ${it.name}")
            // You could generate a fake result or simply skip actual execution
            // Here we simulate by printing a 0ms result
            println("Result: 0ms")
        }
    }
}

使用自定义运行器 您可以使用此自定义运行程序来代替代码中的标准运行程序:

fun main() {
    val options = OptionsBuilder()
        .warmupForks(3)
        .forks(2)
        .mode(Mode.Throughput)
        .resultFormat(ResultFormatType.TEXT)
        .build()

    val runner = DryRunRunner(options)
    runner.run()
}

注释

  • BenchmarkList:您需要创建或找到合适的类或方法来列出 DryRunRunner 中的基准。 JMH 不会直接公开这一点,因此您可能需要使用反射或其他方法,具体取决于内部 JMH API。

  • 结果模拟:在 DryRunRunner 中,您可以通过打印 0ms 来模拟结果。您可以自定义它以满足您的需求。

  • 集成测试:如果您还对 JMH 如何测试自身感兴趣,JMH 确实使用一些内部机制进行自己的测试,但它通常照常运行基准测试。您可能找不到用于跳过执行的直接内部测试模式。

通过实施上述方法,您应该能够验证 JMH 是否已正确配置,而无需实际运行基准测试。

© www.soinside.com 2019 - 2024. All rights reserved.