ssu*_*ube 3 java optimization performance java-8 jmh
我有一段代码,在我运行的每个测试中,函数调用都会产生大量的开销.代码是一个紧密的循环,在一个数组的每个元素上执行一个非常简单的函数(包含4-8百万ints).
运行主要由以下内容组成的代码
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);
}
}
Run Code Online (Sandbox Code Playgroud)
执行类似的事情
(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;
};
Run Code Online (Sandbox Code Playgroud)
在各种机器上(我的工作笔记本电脑,带有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
Run Code Online (Sandbox Code Playgroud)
专用服务器,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
Run Code Online (Sandbox Code Playgroud)
做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
Run Code Online (Sandbox Code Playgroud)
所有可接受的性能,但我有兴趣弄清楚为什么呼叫有这么大的开销,以及可以做些什么来优化它.目前正在试验不同的参数集.
列举所有潜在的操作将是困难的,但理论上是可行的.接近2倍的性能提升,可能值得,但维护将是一场噩梦.
我不确定是否有合理的方法来批量重复一组; 大多数操作需要多个输入(调用者不知道)并产生单个输出.
我还有哪些其他选项可以减少开销和夜间性能?
方法调用不是问题,因为热方法经常被内联.一个虚拟的电话是一个问题.
在您的代码中,类型分析器被初始化方法欺骗Image.random.什么时候Image.process第一次进行JIT编译,它会针对调用进行优化random.nextInt().因此,下一次调用Image.process将导致内联缓存未命中,然后是非优化的虚拟调用Shader.apply.
Image.process从初始化方法中删除一个调用,然后JIT将内联有用的调用Shader.apply.
BlurShader.apply在内联之后,您可以帮助JIT 通过替换来执行Common子表达式消除优化
final int p = s * y + x;
Run Code Online (Sandbox Code Playgroud)
同
final int p = y * s + x;
Run Code Online (Sandbox Code Playgroud)
后一个表达式也被满足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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
976 次 |
| 最近记录: |