我有a piece of code出现在我运行的每个测试中,函数调用会产生大量开销。代码是一个紧密循环,对数组的每个元素执行一个非常简单的函数(包含4-8百万int
s)。
运行代码,主要由
组成for (int y = 1; y < h; ++y) {
for (int x = 1; x < w; ++x) {
final int p = y * s + x;
n[p] = f.apply(d, s, x, y);
}
}
执行类似
的操作(final int[] d, final int s, final int x, final int y) -> {
final int p = s * y + x;
final int a = d[p] * 2
+ d[p - 1]
+ d[p + 1]
+ d[p - s]
+ d[p + s];
return (1000 * (a + 500)) / 6000;
};
在各种机器上(我的工作笔记本电脑,带有i7 3840QM的W530,带有Xeon E5-1620核心的服务器VM,以及带有一个未知CPU核心的数字海洋节点),我反复获得统计上的显着性调用方法vs内联时性能上升。所有测试均在Java 1.8.0_11(Java HotSpot(TM)64位服务器VM)上执行。
工作机器:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 40.860 0.184 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 22.603 0.159 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 22.792 0.117 ops/s
专用服务器,VM:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 40.685 0.224 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 16.077 0.113 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 23.827 0.088 ops/s
DO VPS:
Benchmark Mode Samples Score Score error Units
c.s.q.ShaderBench.testProcessInline thrpt 200 24.425 0.506 ops/s
c.s.q.ShaderBench.testProcessLambda thrpt 200 9.643 0.140 ops/s
c.s.q.ShaderBench.testProcessProc thrpt 200 13.733 0.134 ops/s
所有可接受的性能,但我有兴趣弄清楚为什么呼叫有如此大的开销,以及可以做些什么来优化它。目前正在尝试不同的参数集。
列出所有潜在的操作将是困难的,但理论上是可行的。对于接近2倍的性能提升,可能值得,但维护将是一场噩梦。
我不确定是否有合理的方法来批量重复一组;大多数操作都需要多个输入(调用者不知道)并产生单个输出。
我还有哪些其他方法可以减少开销和夜间表现?
答案 0 :(得分:9)
方法调用不是问题,因为热方法经常被内联。 虚拟电话是一个问题。
在您的代码中,类型分析器被初始化方法Image.random
欺骗。当Image.process
第一次进行JIT编译时,它会针对调用random.nextInt()
进行优化。因此,Image.process
的下一次调用将导致内联缓存未命中,然后是对Shader.apply
的非优化虚拟调用。
从初始化方法中删除Image.process
调用,然后JIT将内联对Shader.apply
的有用调用。
内联BlurShader.apply
后,您可以通过替换
final int p = s * y + x;
与
final int p = y * s + x;
后一个表达式也在Image.process
中得到满足,因此JIT不会两次计算相同的表达式。
应用这两项变更后,我已达到理想的基准分数:
Benchmark Mode Samples Mean Mean error Units
s.ShaderBench.testProcessInline thrpt 5 36,483 1,255 ops/s
s.ShaderBench.testProcessLambda thrpt 5 36,323 0,936 ops/s
s.ShaderBench.testProcessProc thrpt 5 36,163 1,421 ops/s