最小化Java函数调用开销

我有一段代码 ,在我运行的每个测试中,函数调用都会产生大量的开销。 代码是一个紧密循环,对数组的每个元素执行一个非常简单的函数(包含4-8百万个int )。

运行代码,主要包含

 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 csqShaderBench.testProcessInline thrpt 200 40.860 0.184 ops/s csqShaderBench.testProcessLambda thrpt 200 22.603 0.159 ops/s csqShaderBench.testProcessProc thrpt 200 22.792 0.117 ops/s 

专用服务器,VM:

 Benchmark Mode Samples Score Score error Units csqShaderBench.testProcessInline thrpt 200 40.685 0.224 ops/s csqShaderBench.testProcessLambda thrpt 200 16.077 0.113 ops/s csqShaderBench.testProcessProc thrpt 200 23.827 0.088 ops/s 

做VPS:

 Benchmark Mode Samples Score Score error Units csqShaderBench.testProcessInline thrpt 200 24.425 0.506 ops/s csqShaderBench.testProcessLambda thrpt 200 9.643 0.140 ops/s csqShaderBench.testProcessProc thrpt 200 13.733 0.134 ops/s 

所有可接受的性能,但我有兴趣弄清楚为什么呼叫有这么大的开销,以及可以做些什么来优化它。 目前正在试验不同的参数集。

列举所有潜在的操作将是困难的,但理论上是可行的。 对于接近2倍的性能提升,可能是值得的,但维护将是一场噩梦。

我不确定是否有合理的方法批评一组重复; 大多数操作需要多个输入(调用者不知道)并产生单个输出。

我还有哪些其他选项可以减少开销和夜间性能?

方法调用不是问题,因为热方法经常被内联。 虚拟呼叫是一个问题。

在您的代码中,类型分析器被初始化方法Image.random欺骗。 当Image.process第一次被JIT编译时,它被优化用于调用random.nextInt() 。 因此, Image.process的下一次调用将导致内联缓存未命中,然后是对Shader.apply的非优化虚拟调用。

  1. 从初始化方法中删除一个Image.process调用,然后JIT将内联对Shader.apply的有用调用。

  2. BlurShader.applyBlurShader.apply之后,您可以帮助JIT通过替换来执行Common子表达式消除优化

     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