内在函数和内联对 Lambda 性能的影响?
Impact of Intrinsics and inlining on Lambda's performance?
我使用了这个基准 java8-lambda-performance-test 并且当 运行 它时我做了以下事情:
1.Disabled 内部用法
2.Disabled 内联
3.Disabled 编译中
模式
我发现禁用前两个优化对结果没有影响。
这很奇怪,而且当 运行 基准测试和 print intrinsic 时,我没有发现任何对 intrinsic compiledLambdaForm
的调用
由于那里大量使用数学内在函数 _min,_pow...我原以为禁用内在函数会降低性能
我不认为内在函数有任何影响,因为 Lambda 表达式主要使用 class LambdaMetaFactory.
所以这就是为什么内联和内在函数对 lambda 本身没有影响.
现在对于数学内在函数,我认为由于它们仅用于身份方法,仅用于 LambdaExtraAverage
和 LambdaExtraSerial
测试,因此它们不会产生太大影响基准测试结果。
您没有注意到预期性能效果的原因是 poorly written benchmark。
我使用 JMH 重写了基准测试,结果终于正确了。
package lambdademo;
import org.openjdk.jmh.annotations.*;
import java.util.List;
@State(Scope.Benchmark)
public class LambdaBenchmark {
@Param("100")
private static int loopCount;
private static double identity(double val) {
double result = 0;
for (int i=0; i < loopCount; i++) {
result += Math.sqrt(Math.abs(Math.pow(val, 2)));
}
return result / loopCount;
}
private List<EmployeeRec> employeeList = new EmployeeFile().loadEmployeeList();
@Benchmark
public double streamAverage() {
return streamAverageNoInline();
}
@Benchmark
@Fork(jvmArgs = "-XX:-Inline")
public double streamAverageNoInline() {
return employeeList.stream()
.filter(s -> s.getGender().equals("M"))
.mapToDouble(s -> s.getAge())
.average()
.getAsDouble();
}
@Benchmark
public double streamMath() {
return streamMathNoIntrinsic();
}
@Benchmark
@Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DisableIntrinsic=_dpow,_dabs,_dsqrt"})
public double streamMathNoIntrinsic() {
return employeeList.stream()
.filter(s -> s.getGender().equals("M"))
.mapToDouble(s -> identity(s.getAge()))
.average()
.getAsDouble();
}
}
结果如下:
Benchmark Mode Cnt Score Error Units
LambdaBenchmark.streamAverage avgt 5 71,490 ± 0,770 ms/op
LambdaBenchmark.streamAverageNoInline avgt 5 122,740 ± 0,576 ms/op
LambdaBenchmark.streamMath avgt 5 92,672 ± 1,538 ms/op
LambdaBenchmark.streamMathNoIntrinsic avgt 5 5747,007 ± 20,387 ms/op
正如预期的那样,-XX:-Inline
的基准运行时间延长了 70%,而禁用 Math intrinsics 的版本似乎慢了 60 倍!
我使用了这个基准 java8-lambda-performance-test 并且当 运行 它时我做了以下事情:
1.Disabled 内部用法
2.Disabled 内联
3.Disabled 编译中 模式
我发现禁用前两个优化对结果没有影响。
这很奇怪,而且当 运行 基准测试和 print intrinsic 时,我没有发现任何对 intrinsic compiledLambdaForm
由于那里大量使用数学内在函数 _min,_pow...我原以为禁用内在函数会降低性能
我不认为内在函数有任何影响,因为 Lambda 表达式主要使用 class LambdaMetaFactory.
所以这就是为什么内联和内在函数对 lambda 本身没有影响.
现在对于数学内在函数,我认为由于它们仅用于身份方法,仅用于 LambdaExtraAverage
和 LambdaExtraSerial
测试,因此它们不会产生太大影响基准测试结果。
您没有注意到预期性能效果的原因是 poorly written benchmark。
我使用 JMH 重写了基准测试,结果终于正确了。
package lambdademo;
import org.openjdk.jmh.annotations.*;
import java.util.List;
@State(Scope.Benchmark)
public class LambdaBenchmark {
@Param("100")
private static int loopCount;
private static double identity(double val) {
double result = 0;
for (int i=0; i < loopCount; i++) {
result += Math.sqrt(Math.abs(Math.pow(val, 2)));
}
return result / loopCount;
}
private List<EmployeeRec> employeeList = new EmployeeFile().loadEmployeeList();
@Benchmark
public double streamAverage() {
return streamAverageNoInline();
}
@Benchmark
@Fork(jvmArgs = "-XX:-Inline")
public double streamAverageNoInline() {
return employeeList.stream()
.filter(s -> s.getGender().equals("M"))
.mapToDouble(s -> s.getAge())
.average()
.getAsDouble();
}
@Benchmark
public double streamMath() {
return streamMathNoIntrinsic();
}
@Benchmark
@Fork(jvmArgs = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DisableIntrinsic=_dpow,_dabs,_dsqrt"})
public double streamMathNoIntrinsic() {
return employeeList.stream()
.filter(s -> s.getGender().equals("M"))
.mapToDouble(s -> identity(s.getAge()))
.average()
.getAsDouble();
}
}
结果如下:
Benchmark Mode Cnt Score Error Units
LambdaBenchmark.streamAverage avgt 5 71,490 ± 0,770 ms/op
LambdaBenchmark.streamAverageNoInline avgt 5 122,740 ± 0,576 ms/op
LambdaBenchmark.streamMath avgt 5 92,672 ± 1,538 ms/op
LambdaBenchmark.streamMathNoIntrinsic avgt 5 5747,007 ± 20,387 ms/op
正如预期的那样,-XX:-Inline
的基准运行时间延长了 70%,而禁用 Math intrinsics 的版本似乎慢了 60 倍!