Java JMH基准迭代中的随机峰值

Java JMH基准迭代中的随机峰值,java,garbage-collection,microbenchmark,jmh,Java,Garbage Collection,Microbenchmark,Jmh,我正在尝试测试一种非常快速的方法(~20 us/op),它似乎工作得很好,除了一些迭代,它们是随机的非常长的: Iteration 63: 14.319 us/op Iteration 64: 13.128 us/op Iteration 65: 15.198 us/op Iteration 66: 20.822 us/op Iteration 67: 21.669 us/op Iteration 68: 21.439 us/op Iteration 69: 15.946 us/o

我正在尝试测试一种非常快速的方法(~20 us/op),它似乎工作得很好,除了一些迭代,它们是随机的非常长的:

Iteration  63: 14.319 us/op
Iteration  64: 13.128 us/op
Iteration  65: 15.198 us/op
Iteration  66: 20.822 us/op
Iteration  67: 21.669 us/op
Iteration  68: 21.439 us/op
Iteration  69: 15.946 us/op
Iteration  70: 18.793 us/op
Iteration  71: 19.212 us/op
Iteration  72: 816.129 us/op  // oopsy
Iteration  73: 22.115 us/op
Iteration  74: 15.143 us/op
Iteration  75: 18.423 us/op
Iteration  76: 15.238 us/op

Result "benchmark.StuffBench.run_bench":
  20.629 ±(99.9%) 9.164 us/op [Average]
  (min, avg, max) = (12.689, 20.629, 816.129), stdev = 47.763
  CI (99.9%): [11.464, 29.793] (assumes normal distribution)
它可能是GC,但
shouldDoGc(false)
不会改变任何东西:

final Options options = new OptionsBuilder()
                .include(StuffBench.class.getSimpleName())
                .shouldDoGC(false)
                .build();
Collection<RunResult> runResults = new Runner(options).run();

为了解决这类问题,我使用了我称之为抖动采样器的东西。您有一个线程设置时间戳、运行代码、重置时间戳并暂停以避免CPU过载。第二个线程对时间戳进行采样,如果时间戳处于活动状态且时间过长(例如20 us),则打印它正在执行的堆栈跟踪。e、 g.Thread.getStackTrace()结合最常见的堆栈跟踪,您就有了一个可以指向问题的安全点(或问题后的第一个安全点)。这比科学更艺术;)

谢谢@Peter,这对我来说有点抽象,但如果您使用时间戳来衡量性能,我想您不会使用JMH吧?或者,这只是一种找出峰值原因的临时方法?@Pleymor,这是一种找出峰值原因的简单方法。我使用
System.nanoTime()
分配给
volatile long
字段。
@Fork(value = 2)
@Threads(1)
@Warmup(iterations = 1000, time = 50, timeUnit = TimeUnit.MICROSECONDS)
@Measurement(iterations = 150, time = 50, timeUnit = TimeUnit.MICROSECONDS)
@Timeout(time = 50, timeUnit = TimeUnit.MICROSECONDS)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@State(Scope.Benchmark)
public class StuffBench {
    private Stuff stuff;

    @Setup
    public void initialize() {
        stuff = new Stuff();
    }

    @Benchmark
    public void run_bench() {
        stuff.run();
    }
}