CPU的div指令和HotSpot的JIT代码之间存在较大的性能差距

Mar*_*nik 10 java jmh

从CPU的开始,一般知道整数除法指令是昂贵的.我去看看今天有多糟糕,在拥有数十亿晶体管的CPU上.我发现硬件idiv指令对于常量除数的性能仍然比JIT编译器能够发出的代码差得多,后者不包含idiv指令.

为了在专用的微基准测试中实现这一点,我写了以下内容:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@OperationsPerInvocation(MeasureDiv.ARRAY_SIZE)
@Warmup(iterations = 8, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@State(Scope.Thread)
@Fork(1)
public class MeasureDiv
{
  public static final int ARRAY_SIZE = 128;
  public static final long DIVIDEND_BASE = 239520948509234807L;
  static final int DIVISOR = 10;
  final long[] input = new long[ARRAY_SIZE];

  @Setup(Level.Iteration) public void setup() {
    for (int i = 0; i < input.length; i++) {
      input[i] = DIVISOR;
    }
  }

  @Benchmark public long divVar() {
    long sum = 0;
    for (int i = 0; i < ARRAY_SIZE; i++) {
      final long in = input[i];
      final long dividend = DIVIDEND_BASE + i;
      final long divisor = in;
      final long quotient = dividend / divisor;
      sum += quotient;
    }
    return sum;
  }

  @Benchmark public long divConst() {
    long sum = 0;
    for (int i = 0; i < ARRAY_SIZE; i++) {
      final long in = input[i];
      final long dividend = DIVIDEND_BASE + in;
      final int divisor = DIVISOR;
      final long quotient = dividend / divisor;
      sum += quotient;
    }
    return sum;
  }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,我有两个方法在每个方面都相同,除了one(divVar)通过读取数组的数字执行除法,而另一个除以编译时常量.这些是结果:

Benchmark            Mode  Cnt  Score   Error  Units
MeasureDiv.divConst  avgt    5  1.228 ± 0.032  ns/op
MeasureDiv.divVar    avgt    5  8.913 ± 0.192  ns/op
Run Code Online (Sandbox Code Playgroud)

性能比非常特别.我的期望是,现代英特尔处理器有足够的空间,而且它的工程师有足够的兴趣,在硬件中实现复杂但高性能的划分算法.然而,JIT编译器通过向其发送一些执行相同工作的其他指令流来击败英特尔,仅快七倍.如果有的话,专用微码应该能够比JIT通过汇编指令的公共API更好地利用CPU.

怎么会idiv这么慢,什么是基本限制?

我想到的一个解释是假设存在一种除法算法,这种算法首次将红利放入过程中.然后,JIT编译器将有一个良好的开端,因为它将评估第一部分,该部分在编译时仅涉及除数,并且仅将算法的第二部分作为运行时代码发出.这个假设是真的吗?

Mar*_*nik 1

正如用户pvg通过评论所解释的那样,假设的算法确实存在,并且是目前已知的最好的算法。该算法在准备步骤中涉及除以相同的除数,因此它作为一个整体基本上是不可约的。经典出版物Hacker's Delight的第 10 章对此进行了介绍。