当前位置: 首页 > 知识库问答 >
问题:

将两个DWORD封装到一个QWORD中以节省存储带宽

常鸿朗
2023-03-14
top:
mov eax, DWORD [rsi]
mov DWORD [rdi], eax
mov eax, DWORD [rdx]
mov DWORD [rdi + 4], eax
; unroll the above a few times
; increment rdi and rsi somehow
cmp ...
jne top

自然出现的一个想法是将两个Dword加载组合到单个Qword存储中,这是可能的,因为存储是连续的。像这样的方法可以奏效:

top:
mov eax, DWORD [rsi]
mov ebx, DWORD [rdx]
shl rbx, 32
or  rax, rbx
mov QWORD [rdi] 

基本上,执行两次加载,并使用两个ALU操作将它们组合成一个qword,我们可以用一个存储库存储它。现在我们遇到了uops的瓶颈:每2个Dwords 5个uops--因此,每个Qword或每个Dword为1.25个循环或每个Dword为0.625个循环。

已经比第一个选项好得多了,但我不禁认为这种洗牌有更好的选择--例如,我们使用普通加载浪费了uop吞吐量--感觉我们应该能够将至少一些ALU操作与带有内存源操作数的加载结合起来,但我在Intel上遇到了很大的困难:内存上的SHL只有一个RMW表单SHLXROLX不进行微融合。

另外,通过使第二次加载的Qword加载偏移量为-4,我们似乎可以免费获得移位,但这样我们就只能清除加载Dword中的垃圾。

我对标量代码感兴趣,并对基本x86-64指令集和更好版本的代码感兴趣,如果可能的话,还有有用的扩展,如BMI

共有1个答案

张嘉熙
2023-03-14

似乎我们可以通过使第二次加载的QWORD加载偏移量为-4,来获得免费的移位,但这样我们就可以清除加载Dword中的垃圾了。

如果对于正确性和性能(高速缓存行拆分…)来说,更宽的负载是可以的,我们可以使用shld

top:
    mov eax, DWORD [rsi]
    mov rbx, QWORD [rdx-4]     ; unaligned(?) 64-bit load

    shld rax, rbx, 32          ; 1 uop on Intel SnB-family, 0.5c recip throughput
    mov QWORD [rdi], rax

MMXpunpckldq mm0,[mem]微保险丝SNB系列(包括Skylake)。

top:
    movd       mm0, DWORD [rsi]
    punpckldq  mm0, QWORD [rdx]     ; 1 micro-fused uop on Intel SnB-family

    movq       QWORD [rdi], mm0

 ; required after the loop, making it only worth-while for long-running loops
 emms

不幸的是,punpckl指令的内存操作数是向量宽度的,而不是半宽度的。这通常会破坏它们本来很完美的用途(尤其是必须对齐16B内存操作数的SSE2版本)。但是请注意MMX版本(只有qword内存操作数)没有对齐要求。

这样一个令人沮丧和无用的设计决定(大概是在装载端口可以免费零扩展之前做出的,并且没有与AVX固定)。至少我们有movhps作为memory-sourcepunpcklqdq的替代品,但是不能替代实际洗牌的更窄的宽度。

为了避免CL-拆分,还可以使用单独的MOVDload和punpckldq,或SSE4.1pinsrd。有了这个,MMX就没有理由了。

top:
    movd       xmm0, DWORD [rsi]

    movd       xmm1, DWORD [rdx]           ; SSE2
    punpckldq  xmm0, xmm1
    ; or pinsrd  xmm0, DWORD [rdx], 1      ; 2 uops not micro-fused

    movq       QWORD [rdi], xmm0

显然,AVX2vpgatherdd是一种可能,并且可能在Skylake上表现良好。

 类似资料:
  • 我正在尝试使用Node将文件从AWS S3存储桶复制到另一个存储桶。问题是,如果文件名没有空格,例如:“abc.csv”,它就可以正常工作。但如果我要复制到的文件名中有空格,例如:“abc xyz.csv”。它抛出了下面的错误。 “指定的密钥不存在。”“NoSuchKey:指定的密钥不存在。应请求。extractError(d:\Projects\Other\testproject\s3filet

  • 问题内容: 我正在将Jenkins管道插件与Jenkinsfile一起使用。 在一个名为vms.git的存储库中,我有Jenkinsfile及其构建的应用程序。 我还有一个名为deploy.git的存储库,其中包含我想用于在vms.git中部署应用程序的脚本。 目前,我的Jenkinsfile看起来像这样 并且我在作业配置中定义了vms.git存储库。 因此,我想做的是检出两个存储库,然后使用vm

  • 我正在使用Jenkins管道插件和Jenkins文件。 在一个名为vms的存储库中。git,我有Jenkinsfile和它构建的应用程序。 我有另一个名为deploy的存储库。git,其中包含我想用于在VM中部署应用程序的脚本。吉特。 目前我的Jenkinsfile就是这样的 我正在作业配置中定义vms.git存储库。 所以我想做的是检查这两个存储库,然后在vms中使用Jenkinsfile。gi

  • 我正在尝试将 json 对象数组反序列化为 java 对象数组。我正在使用数据提供程序将此数据组合传递给测试方法,以便为每个数据集执行测试方法。 我已经创建了下面提到的数据提供程序方法,并对 JSON 进行了删除: 测试方法: 和JSON: 不幸的是,它不起作用。如果我使用如下所示的强类型对象,那么它将按预期工作: 错误: org . TestNG . internal . reflect . m

  • 我有3个节点设置 10.x.x.1-应用程序和文件拍10.x.x.2-用于解析和日志存储的机器10.x.x.3-具有集中的日志存储节点,我们需要从该节点将消息推送到弹性搜索中 10.x.x.3 logstash conf文件 是否有任何插件可以将json数据从一个logstash发送到另一个logstash服务器

  • 问题内容: 有没有办法在Python中将两个装饰器组合成一个新的装饰器? 我意识到我可以将多个装饰器应用于一个函数,但是我很好奇是否有一些简单的方法可以将两个装饰器组合成一个新的装饰器。 问题答案: 更一般一些: 然后 相当于