gpt4 book ai didi

c++ - SSE/优化 - 将数组复制到更大的数组

转载 作者:太空宇宙 更新时间:2023-11-04 11:26:44 26 4
gpt4 key购买 nike

我正在尝试优化以下功能:(基本上它需要一行 32 位 Int,并将每个 int 复制到一个更大的目标数组中,然后复制每一行

for(int i = 0; i < numLines; i++)
{
pStartOfLine = pDest;
for(int j = 0; j < intsPerLineSrc; j++)
{
*pDest = *pSrc; // copy pixel A to FullSizeBuffer A
pDest++; // Move dest Ptr to next Pixel
*pDest = *pSrc; // Copy pixel A to FullsizeBuffer AGAIN

pDest++; // Move Src and Dst Pointrs to next pixels
pSrc++;
}

memcpy(pDest, pStartOfLine, (8*intsPerLineSrc) ); // Duplicate the Line written to pDest, to next line of pDest.
pDest = pDest + (2*intsPerLineSrc); // move pDest to Start of Next Line
}

在两个维度上有效地将图像缩放到 2 * 原始大小。现在,这让我觉得应该从 SIMD 中获益匪浅,但是我似乎找不到可以在这种特定情况下为我提供帮助的正确的内在指令集。

有人愿意帮助我吗?或者我是否会在如此简单的操作中始终受到内存限制,以至于在 SIMD 中重构是一种浪费?

是的,这部分代码最终在多线程中运行,因此它已经是大量多线程的,但我认为 SIMD 优化可能更有帮助。

干杯,任何帮助/建议,

詹姆斯

最佳答案

您当前的操作受内存带宽限制。

如果您能找到一种不处理整个图像而是处理 block (例如 16x16 像素 block 到 32x32 像素 block )并在每个 block 上进行其他计算的方法,那么您可能能够减少内存带宽限制。

但是如果您必须处理整个图像,您应该考虑一些事项来实现最大内存带宽:

  1. 对于内存带宽限制操作,它们不随内核数量缩放,但会缩放 scale with the number of sockets .因此,如果您有双路系统,内存带宽是单路系统的两倍(假设两个路都使用它们通常使用的相同处理器)。然而,实现两倍的带宽can be tricky .
  2. memcpy 函数通常未针对大尺寸复制进行优化。主要原因之一是它的许多实现不使用非临时存储。非临时存储的经验法则是在大小大于最慢缓存大小的两倍时使用它们。假设您的处理器有一个 12 MB 的 L3 缓存。然后,如果目标图像的大小大于 6MB,则应考虑使用非临时存储。这几乎肯定是您的情况,因为您的代码正在写入 32 MB。

这是一个如何同时使用 SSE2 和非时态存储的示例

int main() {
int n = 16;
int *src = (int*)_mm_malloc(n*sizeof(int), 16); //16 byte aligned
int *dst = (int*)_mm_malloc(2*n*sizeof(int), 16); //16 byte aligned
for(int i=0; i<n; i++) src[i] = rand();
for(int i=0; i<n; i+=4) {
__m128i x = _mm_load_si128((__m128i*)&src[i]);
__m128i lo = _mm_shuffle_epi32(x, 0x50); // 0x50 = 1100 in base 4
__m128i hi = _mm_shuffle_epi32(x, 0xfa); // 0xfa = 3322 in base 4
_mm_stream_si128((__m128i*)&dst[2*i+0], lo); //non-temporal store
_mm_stream_si128((__m128i*)&dst[2*i+4], hi); //non-temporal store
//_mm_store_si128((__m128i*)&dst[2*i+0], lo);
//_mm_store_si128((__m128i*)&dst[2*i+4], hi);
}
//for(int i=0; i<n; i++) printf("%x ", src[i]); printf("\n");
//for(int i=0; i<(2*n); i++) printf("%x ", dst[i]); printf("\n");
}

在您的情况下,将 n 替换为像素数。如果 n 不是四的倍数,那么您必须做一些清理工作,我在这里没有做。临时存储必须按 16 字节对齐才能执行此操作,这就是我对齐 dst 的原因。但是,src 不必对齐 16 字节,因此您可以使用 _mm_loadu_si128 而不是对齐 src

一旦您实现了单个线程的最大带宽并假设您有一个多插槽系统,您应该尝试从两个插槽获得最大带宽。我在这方面没有足够的经验来提供帮助,但我认为可以使用 numactl 来实现。参见 why-doesnt-this-code-scale-linearly举个例子。

关于c++ - SSE/优化 - 将数组复制到更大的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26398041/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com