当前位置: 首页 > 面试题库 >

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

秦伯寅
2023-03-14
问题内容

我很好奇是否java.lang.Integer.rotateLeft可以通过使用旋转指令进行优化,并为此编写了基准。结果
尚无定论:比两班制快得多,但比单班制慢一点。所以我用C 重写了它,并得到了差不多的结果。通过进行
编译时,g
-S -Wall -O3我可以在生成的汇编器中看到指令。我的CPU是Intel Core i5。


基准
是很长,肯定不是最好的一段代码,但我不认为这是
打破。还是?根据文档,旋转需要一个周期,
就像换档一样。有人可以解释结果吗?

rotations:  6860
shift:      5100

前两个答案是错误的。gcc和java的JIT都知道旋转指令并使用它们。关于gcc,请参见上面的链接,关于java,
请参见我的Java基准测试及其结果

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

问题答案:

我不知道gcc和java jit是否能够识别SHIFT和OR运算符序列可以简化为ROTATE指令,这很有趣。

g ++编译器展开循环,使用SHIFT immediateROTATE immediate指令(因为您按常数移动和旋转)。

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

movq    %rax, %rbx
salq    $13, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %rdi, %rbp
sarq    $27, %rbp
xorq    %rbx, %rdx

这是在TimeRotate循环展开情况下重复的六个指令序列:

movq    %rdx, %rbx
rorq    $45, %rbx
leaq    (%rbp,%rbx), %rbx
movq    %r8, %rbp
rorq    $49, %rbp
xorq    %rbx, %r9

它们的主要区别在于salq / sarq forSHIFT和rorq for的用法不同,ROTATE
因此您想知道为什么时间不同是正确的。

答案深在Sandy Bridge(您的Core i5
处理器)的微体系结构中,可在INTEL®64和IA-32处理器体系结构
优化参考
手册中找到。Order Number: 248966-026 April 2012

SHIFT无论使用by 1操作码
还是,该指令都有1个周期的延迟by immediate。可以调度从任一Port 0或者Port 1和用于
这个原因具有0.5周期的吞吐量-处理器可以分派和退休
2点SHIFT immediate每一周期的指令。如果ROTATE需要
条件标志的结果(它们不在
gcc生成的代码中),则该指令需要三个微操作;如果不需要,则需要两个微操作(在
您的情况下为两个微操作)。ROTATE但是,该指令只能从中分派
Port 1,因此具有1个周期的吞吐量-处理器每个周期
只能分派和退出一个ROTATE immediate。

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

3.5.1.5按位旋转

按位旋转可以在CL
寄存器中指定的计数旋转,立即数和1位之间进行选择。通常,
立即旋转和寄存器旋转指令比旋转1位要慢。
旋转1指令的延迟与移位相同。
汇编/编译器编码规则35。(ML影响,L通用)避免通过
寄存器进行ROTATE或通过立即指令进行ROTATE。如果可能,用“
ROTATE by 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调度到四个发布端口中的一个或多个。
在微体系结构级别,存储操作进一步分为两
部分:存储数据和存储地址操作。 图2-6
中显示了将μop分配到执行单元以及进行加载和存储操作的四个端口。一些端口每个时钟可以调度两个µop。这些
执行单元标记为Double Speed。

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

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

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

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

每个周期的总发行带宽范围为零到六微欧。每个管道包含几个执行单元。µop将被分派到
与正确操作类型相对应的管道。例如,整数算术逻辑单元和浮点执行单元(加法器,乘法器和除法器)可以共享管线。



 类似资料:
  • 我尝试使用iTextSharp创建一个多页pdf文档。我有一个包含自身方向(横向或纵向)的对象。当第一个对象包含需要横向模式的信息时,我用< code > Document doc = new Document(PageSize。A4.Rotate(),10f,10f,10f,0f)。这工作得很好,直到下一个元素是肖像模式!如果一个元素处于纵向模式,我再次设置页面大小:< code>doc。Set

  • 我正在尝试建立一个简单的“飞鸟”游戏,我需要鸟的图像倾斜,上升时指向上方,反之亦然。然而,当旋转我的图像时,它会在稍微下降或轻触屏幕后部分或完全从屏幕上消失。谁能告诉我怎么解决这个问题吗?

  • 问题内容: 当遇到按位移位运算符时,我遇到了一个有趣的场景。如果第二个操作数为负,按位移位运算如何工作?。 即,<< << b,“ <<”将a中的位模式向左移动b位。但是,如果b为负数,在运行时是否应该出错? 我能够成功运行以下代码,但我不知道它是如何工作的? 输入项 结果 “ a”的ASCII码为97。有人可以帮助我了解其工作原理吗? 问题答案: 但是,如果b为负数,在运行时是否应该出错? 不符

  • 假设我使用大小为8的字符数组来表示图像的碰撞掩码。字符的每一位代表一个像素。实际上,对于64x64矩阵,我将使用长[64]阵列。 因此,框将显示为: 45度的示例输出应该是这样的,尽管旋转可以是任何角度。这个形状对于45度旋转可能不准确,因为我是用手做的。 另一个例子是向右旋转10度?这些值可能是错误的,因为从数学上讲,我不知道它将如何精确旋转,但我认为可以安全地假设,如果每个位的覆盖率超过旧形状

  • 我有一个int < code > 000000000000000000000000001101 ,它代表十进制的13。我试图通过将32位整数视为4位整数来循环旋转这些位,因为如果旋转整数,值会变得非常大。在上面的例子中,右旋转2后,我想要的答案是< code > 00000000000000000000000000111 ,它是以10为基数的7。 非常感谢对此的任何帮助。

  • 问题内容: 我注意到Sun提供了64位版本的Java。它的性能是否比32位版本好? 问题答案: 定义您的工作量以及“表现”对您的意义。 作为一个长期存在的表现极客,这对我来说是种烦恼。特定更改是否“执行得更好”,首先取决于工作量,即您要程序执行的工作。 64位Java通常会在计算量很大的情况下表现更好。Java程序通常具有沉重的I / O负载和沉重的网络负载。64位和32位可能无关紧要,但是操作系