我正在为我编写的浮点打印代码编写 JMH 微基准测试。我还不太关心确切的性能,但要确保基准代码正确。
\n\n我想循环一些随机生成的数据,因此我制作了一些静态数据数组并保持循环机制(增量和掩码)尽可能简单。这是正确的方法还是我应该告诉 JMH 更多关于我缺少的一些注释的情况?
\n\n另外,是否可以为测试制作显示组而不仅仅是字典顺序?我基本上有两组测试(每组随机数据一组。
\n\n完整来源位于https://github.com/jnordwick/zerog-grisu
\n\n这是基准代码:
\n\npackage zerog.util.grisu;\n\nimport java.util.Random;\n\nimport org.openjdk.jmh.annotations.Benchmark;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\n/* \n * Current JMH bench, similar on small numbers (no fast path code yet)\n * and 40% faster on completely random numbers.\n * \n * Benchmark Mode Cnt Score Error Units\n * JmhBenchmark.test_lowp_doubleto thrpt 20 11439027.798 \xc2\xb1 2677191.952 ops/s\n * JmhBenchmark.test_lowp_grisubuf thrpt 20 11540289.271 \xc2\xb1 237842.768 ops/s\n * JmhBenchmark.test_lowp_grisustr thrpt 20 5038077.637 \xc2\xb1 754272.267 ops/s\n * \n …Run Code Online (Sandbox Code Playgroud) java performance-testing microbenchmark floating-point-conversion jmh
我一直在研究 jmh 实现“多线程”基准的方式。根据我的理解,注释@Group("Identifier")和@GroupThreads(thread_number)启用同一组内的基准测试并行运行。
@Benchmark
@Group("parallel")
@GroupThreads(1)
public void benchmark_1() {
while(true) {}
}
@Benchmark
@Group("parallel")
@GroupThreads(1)
public void benchmark_2() {
while(true) {}
}
Run Code Online (Sandbox Code Playgroud)
使用 CPU 监视器,我发现两个 CPU 已充分使用。我想知道跑步者如何解释这些注释。
我正在尝试改进以下代码:
\n public int applyAsInt(String ipAddress) {\n var ipAddressInArray = ipAddress.split("\\\\.");\n ...\nRun Code Online (Sandbox Code Playgroud)\n所以我将正则表达式编译成静态常量:
\n private static final Pattern PATTERN_DOT = Pattern.compile(".", Pattern.LITERAL);\n\n public int applyAsInt(String ipAddress) {\n var ipAddressInArray = PATTERN_DOT.split(ipAddress);\n ...\nRun Code Online (Sandbox Code Playgroud)\n其余代码保持不变。
\n令我惊讶的是,新代码比以前的代码慢。\n以下是测试结果:
\nBenchmark (ipAddress) Mode Cnt Score Error Units\nConverterBenchmark.mkyongConverter 1.2.3.4 avgt 10 166.456 \xc2\xb1 9.087 ns/op\nConverterBenchmark.mkyongConverter 120.1.34.78 avgt 10 168.548 \xc2\xb1 2.996 ns/op\nConverterBenchmark.mkyongConverter 129.205.201.114 avgt 10 180.754 \xc2\xb1 6.891 ns/op\nConverterBenchmark.mkyong2Converter 1.2.3.4 avgt 10 253.318 \xc2\xb1 4.977 ns/op\nConverterBenchmark.mkyong2Converter 120.1.34.78 avgt 10 263.045 \xc2\xb1 8.373 ns/op\nConverterBenchmark.mkyong2Converter …Run Code Online (Sandbox Code Playgroud) 如果我知道那个点的大小,那么传递Collection给Collection构造函数的大小是否更好?扩展Collection和分配/重新分配的节约效果是否显着?
如果我知道最小尺寸Collection而不是上限,该怎么办?至少在最小尺寸的情况下仍然值得创造吗?
如何设置 jmh 参数以便可以在不同的虚拟机上运行测试?
我尝试更改 -jvm //虚拟机的路径。
我收到此错误:
Error parsing command line:
'X' is not a recognized option
<forked VM failed with exit code 1>
<stdout last='20 lines'>
</stdout>
<stderr last='20 lines'>
Error parsing command line:
'X' is not a recognized option
</stderr>
Run Code Online (Sandbox Code Playgroud) 我想知道如果我可以关闭JIT,为什么我应该使用JMH进行基准测试?JMH是否不会抑制可以通过禁用JIT来防止的优化?
我正在阅读JMH框架的示例,我对来自JMHSample_12_Forking的示例代码有疑问.运行此代码后,我有以下结果(正如作者预测的那样):
testJavaUtilConcurrency.JMHSample_12_Forking.measure_1_c1 avgt 5 3.314 ± 0.200 ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c2 avgt 5 22.403 ± 1.023 ns/op
...
Run Code Online (Sandbox Code Playgroud)
该结果解释如下:
注意C1更快,C2更慢,但C1再慢!这是因为 ...
但我的问题是:为什么C2比C1慢?两个类中的代码和两个方法看起来完全相同,那么,性能差异的来源是什么?
更新:
我试图为Counter添加第三个实现并获得以下结果:
testJavaUtilConcurrency.JMHSample_12_Forking.measure_1_c1 avgt 5 3.328 ± 0.073 ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c2 avgt 5 22.437 ± 0.552 ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_2_c3 avgt 5 44.614 ± 5.080 ns/op
testJavaUtilConcurrency.JMHSample_12_Forking.measure_3_c1_again avgt 5 43.535 ± 1.154 ns/op
Run Code Online (Sandbox Code Playgroud) 我正在测量一些单线程方法调用(用 Scala 编写)并想要分析基准测试。这是它的样子(省略了实现细节)
@State(Scope.Benchmark)
class TheBenchmarks {
var data: Array[Byte] = _
@Param(Array("1024", "2048", "4096", "8192"))
var chunkSize: Int = _
@Setup
def setup(): Unit = {
data = //get the data
}
@Benchmark
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Array(Mode.AverageTime))
def takeFirstAvroRecord(bh: Blackhole): Unit = {
val fr = //do computation with data and chunk size
bh.consume(fr)
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,我得到了一些结果并想理解它,但 -prof perfasm我有点不清楚它的输出。首先:
....[Hottest Regions]...............................................................................
44.20% 40.50% runtime stub StubRoutines::jbyte_disjoint_arraycopy (205 bytes)
6.78% 1.62% C2, level 4 cats.data.IndexedStateT$$Lambda$21::apply, version 1242 (967 bytes)
4.39% 0.79% …Run Code Online (Sandbox Code Playgroud) 我采用了一个使用maven-surefire-plugin(自动测试)来触发 JMH 基准测试的项目并将其添加module-info.java到其中。现在,META-INF/BenchmarkList不再生成(实际上,整个目录都丢失了)所以我在启动基准测试时最终出现以下错误:
ERROR: Unable to find the resource: /META-INF/BenchmarkList
我怀疑 Java 模块会阻止注释处理器正常运行,但我不知道如何修复它。有任何想法吗?
我创建了一个类。在那个类中,我有几个方法被标记为@Benchmark. 我还有一个运行 JMH 基准测试的主要方法:
System.out.println("NUMBER OF THREADS: "+numOfThreads);
Options opt = new OptionsBuilder()
.include(JMHtopToBottom.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(3)
.forks(numOfThreads)
.build();
Collection<RunResult> collection = new Runner(opt).run();
Run Code Online (Sandbox Code Playgroud)
我的兴趣是:
只运行一个的设置方法-new Runner(opt).run();在所有@Benchmark方法被调用之后和之前(以及它们的迭代)。
同样,有一个拆卸方法,在所有方法运行之后和我们回到主之前只运行一次。
当我试图@setup和@tear_down(与Level支持:Trial/ Iteration/ Invocation)的方法运行几次,不仅是我希望的。JMH 中是否有一种方法可以注释方法,以便它只运行方法 - 在结束之后run()和之前run()?
我多次注意到,微小的、看似无关的代码更改可以改变一段 Java 代码的性能特征,有时甚至是戏剧性的。
这发生在 JMH 和手动基准测试中。
例如,在这样的类中:
class Class<T> implements Interface {
private final Type field;
Class(ClassBuilder builder) {
field = builder.getField();
}
@Override
void method() { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
我做了这个代码更改:
class Class<T> implements Interface {
private static Class<?> instance;
private final Type field;
Class(Builder builder) {
instance = this;
field = builder.getField();
}
@Override
void method() { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
和性能发生了巨大变化。
这只是一个例子。在其他情况下,我注意到了同样的事情。
我无法确定是什么原因造成的。我在网上搜索,但没有找到任何信息。
对我来说,它看起来完全无法控制。也许这与编译后的代码在内存中的布局有关?
我不认为这是由于错误共享(见下文)。
我正在开发一个自旋锁:
class SpinLock {
@Contended // Add compiler option: --add-exports …Run Code Online (Sandbox Code Playgroud) 我正在使用 JMH 对 JUnit 测试进行基准测试。
我的基准:
import org.openjdk.jmh.annotations.*;
public class Benchmarks {
@Benchmark
public void bmUnitTest1() {
UnitTests.UnitTest1();
}
@Benchmark
public void bmUnitTest2() {
UnitTests.UnitTest2();
}
}
Run Code Online (Sandbox Code Playgroud)
我的基准跑步者:
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.concurrent.TimeUnit;
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(Benchmarks.class.getSimpleName())
.mode(Mode.SingleShotTime)
.resultFormat(ResultFormatType.CSV)
.result("target/test-classes/benchmarkcsv/BM " + System.currentTimeMillis() + ".csv")
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(3)
.warmupTime(TimeValue.seconds(1))
.measurementIterations(3)
.measurementTime(TimeValue.seconds(1))
.timeout(TimeValue.seconds(5))
.forks(1)
.warmupForks(1)
.threads(1)
.build();
new Runner(opt).run(); …Run Code Online (Sandbox Code Playgroud) jmh ×12
java ×10
jvm ×3
performance ×3
benchmarking ×2
collections ×1
java-module ×1
jit ×1
maven ×1
optimization ×1
regex ×1
split ×1