Jmh 为什么我需要黑洞

Jmh 为什么我需要黑洞,jmh,blackhole,Jmh,Blackhole,我试图理解为什么使用Blackhole.consumerCPU()是明智的 我在谷歌--> 有时,当我们跨多个线程运行基准测试时,我们也会 想在运行我们的系统时消耗一些cpu周期来模拟cpu业务吗 代码。这不可能是线程。睡眠,因为我们真的想消耗cpu。这个 Blackhole.consumerCPU(long)为我们提供了这样做的能力 我的示例代码: import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations

我试图理解为什么使用
Blackhole.consumerCPU()
是明智的

我在谷歌-->

有时,当我们跨多个线程运行基准测试时,我们也会 想在运行我们的系统时消耗一些cpu周期来模拟cpu业务吗 代码。这不可能是线程。睡眠,因为我们真的想消耗cpu。这个 Blackhole.consumerCPU(long)为我们提供了这样做的能力

我的示例代码:

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
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;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class StringConcatAvgBenchmark {

StringBuilder stringBuilder1;
StringBuilder stringBuilder2;

StringBuffer stringBuffer1;
StringBuffer stringBuffer2;

String string1;
String string2;

/*
 * re-initializing the value after every iteration
 */
@Setup(Level.Iteration)
public void init() {
    stringBuilder1 = new StringBuilder("foo");
    stringBuilder2 = new StringBuilder("bar");

    stringBuffer1 = new StringBuffer("foo");
    stringBuffer2 = new StringBuffer("bar");

    string1 = new String("foo");
    string2 = new String("bar");

}

@Benchmark
@Warmup(iterations = 10)
@Measurement(iterations = 100)
@BenchmarkMode(Mode.AverageTime)
public StringBuilder stringBuilder() {
    // operation is very thin and so consuming some CPU
    Blackhole.consumeCPU(100);
    return stringBuilder1.append(stringBuilder2);
    // to avoid dead code optimization returning the value
}

@Benchmark
@Warmup(iterations = 10)
@Measurement(iterations = 100)
@BenchmarkMode(Mode.AverageTime)
public StringBuffer stringBuffer() {
    Blackhole.consumeCPU(100);      
    // to avoid dead code optimization returning the value
    return stringBuffer1.append(stringBuffer2);
}

@Benchmark
@Warmup(iterations = 10)
@Measurement(iterations = 100)
@BenchmarkMode(Mode.AverageTime)
public String stringPlus() {
    Blackhole.consumeCPU(100);      
    return string1 + string2;
}

@Benchmark
@Warmup(iterations = 10)
@Measurement(iterations = 100)
@BenchmarkMode(Mode.AverageTime)
public String stringConcat() {
    Blackhole.consumeCPU(100);      
    // to avoid dead code optimization returning the value
    return string1.concat(string2);
}

public static void main(String[] args) throws RunnerException {

    Options options = new OptionsBuilder()
            .include(StringConcatAvgBenchmark.class.getSimpleName())
            .threads(1).forks(1).shouldFailOnError(true).shouldDoGC(true)
            .jvmArgs("-server").build();
    new Runner(options).run();
}
}
为什么使用
blackhole.consumerCPU(100)
这个基准测试的结果会更好

编辑:

使用黑洞输出。消耗CPU(100):

输出无黑洞。消耗CPU(100):

我的问题是,为什么这段代码的作者在这里使用blackhole.consumerCPU(100)

我想我现在知道为什么了,因为基准太快了,没有任何延迟

使用
blackhole.consumerCPU(100)
可以更好地测量每个基准,并获得更重要的结果


是吗?

添加人工延迟通常不会改善基准

但是,在某些情况下,您正在测量的操作正在争夺一些资源,您需要一个只消耗CPU的退避,希望不做其他事情。例如,参见以下案例:

原始问题中的基准并非如此,因此我推测黑洞的使用没有很好的理由,或者至少在评论中没有特别提到这个理由。不要那样做。

定义“更好”?我看不出你的问题有什么可比性。
Benchmark                      Mode  Cnt    Score    Error  Units
StringBenchmark.stringBuffer   avgt   10  398,843 ± 38,666  ns/op
StringBenchmark.stringBuilder  avgt   10  387,543 ± 40,087  ns/op
StringBenchmark.stringConcat   avgt   10  410,256 ± 33,194  ns/op
StringBenchmark.stringPlus     avgt   10  386,472 ± 21,704  ns/op
Benchmark                      Mode  Cnt   Score    Error  Units
StringBenchmark.stringBuffer   avgt   10  51,225 ± 19,254  ns/op
StringBenchmark.stringBuilder  avgt   10  49,548 ±  4,126  ns/op
StringBenchmark.stringConcat   avgt   10  50,373 ±  1,408  ns/op
StringBenchmark.stringPlus     avgt   10  87,942 ±  1,701  ns/op