最近我有一个非常奇怪的事情 - 一个方法在profiler下非常慢,没有明显的原因.它包含很少的操作long,但是被频繁调用 - 它的总体使用率约占总程序时间的30-40%,而其他部分看起来要"更重".
我通常在x32 JVM上运行非内存饥饿的程序,但假设我遇到了64位类型的问题,我尝试在x64 JVM上运行相同的程序 - "实时场景"中的整体性能提高了2-3倍.之后我用特定方法为操作创建了JMH基准测试,并对x32和x64 JVM的差异感到震惊 - 高达50次.
我会"接受"x32 JVM(较小的字号)大约慢2倍,但我没有30-50次可能来自的线索.你能解释一下这个巨大的差异吗?
对评论的回复:
所以似乎我的问题的答案是
以下是结果(注意:? 10??特殊字符不是在Windows上打印的 - 它是低于0.001 s/op用科学记数法写成的10e- ??)
x32 1.8.0_152
Benchmark Mode Score Units Score (with 'return')
IntVsLong.cycleInt avgt 0.035 s/op 0.034 (?x slower vs. x64)
IntVsLong.cycleLong avgt 0.106 s/op 0.099 (3x slower vs. x64)
IntVsLong.divDoubleInt avgt 0.462 s/op 0.459
IntVsLong.divDoubleLong avgt 1.658 s/op 1.724 (2x slower vs. x64)
IntVsLong.divInt avgt 0.335 s/op 0.373
IntVsLong.divLong avgt 1.380 s/op 1.399
IntVsLong.l2i avgt 0.101 s/op 0.197 (3x slower vs. x64)
IntVsLong.mulInt avgt 0.067 s/op 0.068
IntVsLong.mulLong avgt 0.278 s/op 0.337 (5x slower vs. x64)
IntVsLong.subInt avgt 0.067 s/op 0.067 (?x slower vs. x64)
IntVsLong.subLong avgt 0.243 s/op 0.300 (4x slower vs. x64)
x64 1.8.0_152
Benchmark Mode Score Units Score (with 'return')
IntVsLong.cycleInt avgt ? 10?? s/op ? 10??
IntVsLong.cycleLong avgt 0.035 s/op 0.034
IntVsLong.divDoubleInt avgt 0.045 s/op 0.788 (was dead)
IntVsLong.divDoubleLong avgt 0.033 s/op 0.787 (was dead)
IntVsLong.divInt avgt ? 10?? s/op 0.302 (was dead)
IntVsLong.divLong avgt 0.046 s/op 1.098 (was dead)
IntVsLong.l2i avgt 0.037 s/op 0.067
IntVsLong.mulInt avgt ? 10?? s/op 0.052 (was dead)
IntVsLong.mulLong avgt 0.040 s/op 0.067
IntVsLong.subInt avgt ? 10?? s/op ? 10??
IntVsLong.subLong avgt 0.075 s/op 0.082
Run Code Online (Sandbox Code Playgroud)
这是(固定)基准代码
import org.openjdk.jmh.annotations.Benchmark;
public class IntVsLong {
public static int N_REPEAT_I = 100_000_000;
public static long N_REPEAT_L = 100_000_000;
public static int CONST_I = 3;
public static long CONST_L = 3;
public static double CONST_D = 3;
@Benchmark
public void cycleInt() throws InterruptedException {
for( int i = 0; i < N_REPEAT_I; i++ ) {
}
}
@Benchmark
public void cycleLong() throws InterruptedException {
for( long i = 0; i < N_REPEAT_L; i++ ) {
}
}
@Benchmark
public int divInt() throws InterruptedException {
int r = 0;
for( int i = 0; i < N_REPEAT_I; i++ ) {
r += i / CONST_I;
}
return r;
}
@Benchmark
public long divLong() throws InterruptedException {
long r = 0;
for( long i = 0; i < N_REPEAT_L; i++ ) {
r += i / CONST_L;
}
return r;
}
@Benchmark
public double divDoubleInt() throws InterruptedException {
double r = 0;
for( int i = 1; i < N_REPEAT_L; i++ ) {
r += CONST_D / i;
}
return r;
}
@Benchmark
public double divDoubleLong() throws InterruptedException {
double r = 0;
for( long i = 1; i < N_REPEAT_L; i++ ) {
r += CONST_D / i;
}
return r;
}
@Benchmark
public int mulInt() throws InterruptedException {
int r = 0;
for( int i = 0; i < N_REPEAT_I; i++ ) {
r += i * CONST_I;
}
return r;
}
@Benchmark
public long mulLong() throws InterruptedException {
long r = 0;
for( long i = 0; i < N_REPEAT_L; i++ ) {
r += i * CONST_L;
}
return r;
}
@Benchmark
public int subInt() throws InterruptedException {
int r = 0;
for( int i = 0; i < N_REPEAT_I; i++ ) {
r += i - r;
}
return r;
}
@Benchmark
public long subLong() throws InterruptedException {
long r = 0;
for( long i = 0; i < N_REPEAT_L; i++ ) {
r += i - r;
}
return r;
}
@Benchmark
public long l2i() throws InterruptedException {
int r = 0;
for( long i = 0; i < N_REPEAT_L; i++ ) {
r += (int)i;
}
return r;
}
}
Run Code Online (Sandbox Code Playgroud)
有很多变量需要检查。
如果我们只关注使用 64 位的处理器,您可以在同一步骤中对 CPU 寄存器进行更多操作,因为它使用每个寄存器的 8 个八位字节而不是 4 个八位字节。这提高了操作性能和内存分配。此外,某些 CPU 仅启用仅在 64 位模式下运行的高级功能
如果您使用相同的 CPU 来执行测试,则需要考虑到要执行 32 位指令,CPU 需要在虚拟模式或保护模式下运行,这些模式运行速度比真正的 32 位 CPU 慢。此外,某些指令集扩展可能无法使用 32 位模式(如 SSE-SIMD 或 AVX)启用,但可以提高某些操作速度。
如果您使用的是 Windows 10 等现代操作系统,您还需要考虑到该操作系统使用 WOW64(x86 模拟器)运行 32 位应用程序
帮助文档:
| 归档时间: |
|
| 查看次数: |
202 次 |
| 最近记录: |