该结果我的基准测试表明,性能最差的时候该分支下有15%(或85%)%的概率,而不是50%.
任何解释?

代码太长但相关部分在这里:
private int diff(char c) {
return TABLE[(145538857 * c) >>> 27] - c;
}
@Benchmark int timeBranching(int reps) {
int result = 0;
while (reps-->0) {
for (final char c : queries) {
if (diff(c) == 0) {
++result;
}
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
它计算给定字符串中BREAKING_WHITESPACE字符的数量.结果显示当分支概率达到约0.20时突然下降(性能增加).
关于跌落的更多细节.改变种子表明发生了更多奇怪的事情.请注意,表示最小值和最大值的黑线非常短,除非靠近悬崖.

maa*_*nus 10
它看起来像一个小的JIT bug.对于小分支概率,它会产生类似下面的内容,因为展开会更加复杂(我简化了很多):
movzwl 0x16(%r8,%r10,2),%r9d
Run Code Online (Sandbox Code Playgroud)
获取char: int r9d = queries[r10]
imul $0x8acbf29,%r9d,%ebx
Run Code Online (Sandbox Code Playgroud)
乘: ebx = 145538857 * r9d
shr $0x1b,%ebx
Run Code Online (Sandbox Code Playgroud)
转移: ebx >>>= 27
cmp %edx,%ebx
jae somewhere
Run Code Online (Sandbox Code Playgroud)
检查边界:( if (ebx > edx || ebx < 0) goto somewhere然后扔一个IndexOutOfBoundsException.
cmp %r9d,%ebx
jne back
Run Code Online (Sandbox Code Playgroud)
如果不相等,则跳回循环开始: if (r9d != ebx) goto back
inc %eax
Run Code Online (Sandbox Code Playgroud)
增加结果: eax++
jne back
Run Code Online (Sandbox Code Playgroud)
只是 goto back
我们可以看到一个聪明和一个愚蠢的事情:
对于超过20%的分支概率,这三个指令
cmp %r9d,%ebx
jne back
inc %eax
Run Code Online (Sandbox Code Playgroud)
被类似的东西取代
mov %eax,%ecx // ecx = result
inc %ecx // ecx++
cmp %r9d,%ebx // if (r9b == index)
cmoveq %ecx,%ebx // result = ecx
Run Code Online (Sandbox Code Playgroud)
使用条件移动指令.这是一条指令,但没有分支,因此没有分支错误预测惩罚.
这解释了20-80%范围内非常恒定的时间.低于20%的增长显然是由于分支机构的错误预测.
所以看起来JIT没有使用大约0.04而不是0.18的正确阈值.

| 归档时间: |
|
| 查看次数: |
521 次 |
| 最近记录: |