Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 位旋转是否比当前Intel CPU上的移位慢?_Java_Assembly_Rotation_Bit Shift - Fatal编程技术网

Java 位旋转是否比当前Intel CPU上的移位慢?

Java 位旋转是否比当前Intel CPU上的移位慢?,java,assembly,rotation,bit-shift,Java,Assembly,Rotation,Bit Shift,我很好奇java.lang.Integer.rotateLeft是否通过使用旋转指令进行优化并为其编写基准测试。结果是不确定的:它比两个班次快得多,但比一个班次慢一点。所以我用C++重新编写了,得到了同样的结果。通过g++-S-Wall-O3进行编译时,我可以在中看到指令。我的CPU是Intel Core i5 这段代码相当长,肯定不是最好的代码,但我不认为它是坏的。还是这样?根据文献记载,旋转需要一个周期,就像移位一样。有人能解释结果吗 rotations: 6860 shift:

我很好奇
java.lang.Integer.rotateLeft
是否通过使用旋转指令进行优化并为其编写基准测试。结果是不确定的:它比两个班次快得多,但比一个班次慢一点。所以我用C++重新编写了,得到了同样的结果。通过
g++-S-Wall-O3进行编译时,我可以在中看到指令。我的CPU是Intel Core i5

这段代码相当长,肯定不是最好的代码,但我不认为它是坏的。还是这样?根据文献记载,旋转需要一个周期,就像移位一样。有人能解释结果吗

rotations:  6860
shift:      5100

前两个答案是错误的。gcc和java的JIT都知道并使用旋转指令。关于gcc,请参见上面的链接;关于java,请参见my及其结果

benchmark   ns linear runtime
   Rotate 3.48 ====================
NonRotate 5.05 ==============================
    Shift 2.16 ============

我不知道gcc和JavaJIT能够识别移位和或运算符序列可以简化为旋转指令,这非常有趣

g++编译器展开循环,并使用
SHIFT immediate
ROTATE immediate
指令(因为您通过常量值进行移位和旋转)

以下是在TimeShift循环展开情况下重复的六条指令序列:

movq    %rax, %rbx
salq    $13, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %rdi, %rbp
sarq    $27, %rbp
xorq    %rbx, %rdx
movq    %rdx, %rbx
rorq    $45, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %r8, %rbp
rorq    $49, %rbp
xorq    %rbx, %r9
以下是在TimeRotate循环展开案例中重复的六条指令序列:

movq    %rax, %rbx
salq    $13, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %rdi, %rbp
sarq    $27, %rbp
xorq    %rbx, %rdx
movq    %rdx, %rbx
rorq    $45, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %r8, %rbp
rorq    $49, %rbp
xorq    %rbx, %r9
它们的主要区别在于对
SHIFT
使用salq/sarq和对
ROTATE
使用rorq,因此您想知道为什么计时不同是正确的

答案深藏在Sandy Bridge(您的核心i5处理器)的微体系结构中,可以在中找到 最新订单号为:248966-026 2012年4月

SHIFT
指令有一个周期延迟,无论您是按1
操作码使用
,还是按立即数使用
。它可以从
端口0
端口1
进行调度,因此具有0.5个周期的吞吐量-处理器可以在每个周期调度和退出两条
移位立即
指令。如果需要条件标志的结果(它们不在gcc生成的代码中),则
ROTATE
指令需要三个微操作;如果不需要,则需要两个微操作(因此在您的情况下需要两个微操作)。但是,
ROTATE
指令只能从
端口1
发送,因此具有1个周期的吞吐量-处理器每个周期只能发送和退出一个
ROTATE immediate

我已经复制了下面的相关图片和部分

3.5.1.5位旋转

按位旋转可以选择在CL寄存器中指定计数的旋转和 立即常数和1位。通常,按立即数旋转和按 寄存器指令比旋转慢1位。“按1旋转”指令无效 与移位相同的延迟。 汇编/编译器编码规则35。(ML冲击,L一般性)避免旋转 通过注册或根据即时指令轮换。如有可能,更换为 按1指令旋转。 在代号为Sandy Bridge的英特尔微体系结构中,立即数表示的ROL/ROR有1- 循环吞吐量,SHLD/SHRD,使用与源和目标相同的寄存器 即时常数具有1个周期的延迟和0.5个周期的吞吐量。“ROL/ROR” reg,imm8“指令有两个微操作,循环延迟为1个周期 如果使用,则为标志注册结果和2个周期。 在代号为Ivy Bridge的英特尔微体系结构中,立即数大于1的“ROL/ROR reg,imm8”指令是一个微操作,当 使用溢出标志结果。当立即数为1时,依赖于溢出 后续指令的ROL/ROR标记结果将显示ROL/ROR指令 具有两个周期的延迟

2.4.4.2执行单元和发行端口

在每个周期,核心可向四个问题端口中的一个或多个发送µops。在 在微体系结构级别,存储操作进一步分为两个部分:存储 数据和存储地址操作。发送μops的四个端口 图2-6显示了执行单元和加载和存储操作。一些 端口可以为每个时钟分配两个µops。这些执行单元被标记为Double 速度

端口0。在周期的前半部分,端口0可以分派一个浮点值 moveµop(浮点堆栈移动、浮点交换或浮点 存储数据)或一个算术逻辑单元(ALU)µop(算术、逻辑、分支或存储 数据)。在循环的后半部分,它可以调度一个类似的ALUµop

端口1。在循环的前半部分,端口1可以分派一个浮点值 执行(除移动、所有SIMD操作外的所有浮点操作)µop或 一个正常速度整数(乘法、移位和旋转)µop或一个ALU(算术) µop。在循环的后半部分,它可以调度一个类似的ALUµop

端口2。此端口支持每个周期调度一次负载操作

端口3。此端口支持每个周期分派一个存储地址操作

总问题带宽的范围为每周期0到6µops。每条管道 包含多个执行单元。µops被分派到与正确操作类型对应的管道。例如,整数算术逻辑单元 浮点执行单元(加法器、乘法器和除法器)可以共享一个 管道


< P>当你查看微基准时,你必须考虑JIT会优化常见的模式,例如SHIFT,它比不常见的模式更有效地识别,例如旋转(或者它不识别),这意味着两个操作应该花费相同的时间可以完全不同。