如何最有效地存储__m128i / __ m256i的一部分,同时忽略开头/结尾的某些元素

问题描述 投票:2回答:1

我的处理器是Intel 9700K。

我的__m128i__m256i包含charshortint。我需要编写一个store函数,该函数从头开始,从头开始或者从头到尾都忽略给定数量的元素。

对于ints及更高版本,我使用_mm_maskstore_epi32,尽管我想提高它的性能,但还不错。

但是对于较小的类型,我最初使用_mm_maskmoveu_si128,它非常慢 -用我尝试的第一个代码将其替换为short:使用_mm_maskstore_epi32 +在带有早午餐的标量中存储1个短整数,可将性能提高10倍。

所以,我的问题是:

  1. 我怀疑我是第一个需要此功能的人-也许有众所周知的方法吗?
  2. _mm_maskstore_epi32接受int*。是否要求此int*对齐4个字节?也许这是要求,它必须与16个字节对齐(对于256位寄存器为32个字节)?互联网对此并不十分清楚。

我主要关心的是256位寄存器而不是128位寄存器。

UPD:我只在数组边界上使用蒙版。问题是-即使在1kb的阵列上,这也完全控制了我的性能(遍历1kb的数据并计算值并不像我在侧面处理存储那样重要)。我尝试了一个更简单的替代方法-只是为不被忽略的元素调用memcpy,它比我聪明的mask_store骇客要快(可能是因为我不需要为mask_store准备遮罩)。我可能需要类似专门的memcpy之类的东西来存储少于32个字节的数据。

x86 x86-64 simd avx2
1个回答
1
投票

有几种不同的处理数据大小的方法,而不是整个SIMD向量的倍数。这是三种可能性:

  1. 标量清理

    • 使用SIMD处理整个向量
    • 使用标量代码最后处理部分矢量
    • pro:易于实现
    • con:除非没有SIMD迭代,否则没有效率>>没有标量迭代,没有效率
  2. 屏蔽的最终SIMD迭代

    • 使用SIMD处理整个向量
    • 使用SIMD和掩码处理部分矢量,以将新的输出值与超出范围的原始输出值合并(融合)
    • pro:比标量清理更有效
    • con:更复杂,一些代码重复
    • 与load / blend / store一致:如果数组之外的数据以非原子方式读取,修改,写入,则可能不是线程安全的,如果其他线程可能正在触摸它。如果矢量未对齐,则也可以触摸未映射的页面。具有错误抑制功能的适当屏蔽存储(如AVX512或_mm_maskstore_epi32)可以避免这两个问题。
  3. 重叠最终向量

    • 使用SIMD处理整个向量
    • 对于最终的SIMD向量使用重叠,使得向量从n - vector_size开始(即,最后两个向量将重叠)
    • pro:易于实现,从不访问边界之外的元素
    • con:仅适用于n >= vector_size

选择方法将取决于许多因素,但主要取决于n的典型大小和范围。

© www.soinside.com 2019 - 2024. All rights reserved.