gpt4 book ai didi

c++ - 在 C++ 中复制跨步数据

转载 作者:可可西里 更新时间:2023-11-01 15:49:16 32 4
gpt4 key购买 nike

我有两个数组,我想大步将一个数组复制到另一个数组中。例如,我有

A A A A A A A A ...

B B B B B B B B ...

我想将B的每三个元素复制到A中得到

B A A B A A B A ...

从帖子“Is there a standard, strided version of memcpy?”来看,在C中似乎没有这种可能性。

但是,根据我的经验,在某些情况下,memcpy 比基于 for 循环的复制更快。

我的问题是; 有没有什么方法可以在 C++ 中高效地执行跨步内存复制,至少执行标准 for 循环

非常感谢。

编辑 - 问题的澄清

为了使问题更清楚,让我们用ab 表示手边的两个数组。我有一个函数可以执行以下独特的 for 循环

for (int i=0; i<NumElements, i++)
a_[i] = b_[i];

其中 [] 都是重载运算符(我正在使用表达式模板技术),因此它们实际上可以是意思,例如

 a[3*i]=b[i];

最佳答案

可能是一个过于具体的答案,但在支持 NEON 的 ARM 平台上,NEON 向量化可用于更快地进行跨步复制。在资源相对有限的环境中,这可能会挽救生命,这可能就是为什么首先在该环境中使用 ARM 的原因。一个突出的例子是 Android,其中大多数设备仍然使用支持 NEON 的 ARM v7a 架构。

下面的例子演示了这一点,将YUV420sp图像的半平面UV平面复制到YUV420p图像的平面UV平面是一个循环。源缓冲区和目标缓冲区的大小均为 640*480/2 字节。所有示例均使用 Android NDK r9d 中的 g++ 4.8 编译。它们在三星 Exynos Octa 5420 处理器上执行:

1 级:常规

void convertUVsp2UVp(
unsigned char* __restrict srcptr,
unsigned char* __restrict dstptr,
int stride)
{
for(int i=0;i<stride;i++){
dstptr[i] = srcptr[i*2];
dstptr[i + stride] = srcptr[i*2 + 1];
}
}

仅使用 -O3 编译,平均耗时约 1.5 毫秒。

第 2 级:通过移动指针进一步展开和挤压

void convertUVsp2UVp(
unsigned char* __restrict srcptr,
unsigned char* __restrict dstptr,
int stride)
{
unsigned char* endptr = dstptr + stride;
while(dstptr<endptr){
*(dstptr + 0) = *(srcptr + 0);
*(dstptr + stride + 0) = *(srcptr + 1);
*(dstptr + 1) = *(srcptr + 2);
*(dstptr + stride + 1) = *(srcptr + 3);
*(dstptr + 2) = *(srcptr + 4);
*(dstptr + stride + 2) = *(srcptr + 5);
*(dstptr + 3) = *(srcptr + 6);
*(dstptr + stride + 3) = *(srcptr + 7);
*(dstptr + 4) = *(srcptr + 8);
*(dstptr + stride + 4) = *(srcptr + 9);
*(dstptr + 5) = *(srcptr + 10);
*(dstptr + stride + 5) = *(srcptr + 11);
*(dstptr + 6) = *(srcptr + 12);
*(dstptr + stride + 6) = *(srcptr + 13);
*(dstptr + 7) = *(srcptr + 14);
*(dstptr + stride + 7) = *(srcptr + 15);
srcptr+=16;
dstptr+=8;
}
}

仅使用 -O3 编译,平均耗时约 1.15 毫秒。根据其他答案,这可能与常规架构一样快。

3 级:常规 + GCC 自动 NEON 矢量化

void convertUVsp2UVp(
unsigned char* __restrict srcptr,
unsigned char* __restrict dstptr,
int stride)
{
for(int i=0;i<stride;i++){
dstptr[i] = srcptr[i*2];
dstptr[i + stride] = srcptr[i*2 + 1];
}
}

使用 -O3 -mfpu=neon -ftree-vectorize -ftree-vectorizer-verbose=1 -mfloat-abi=softfp 编译,平均耗时约 0.6 毫秒。作为引用,一个 640*480 字节的 memcpy,或者是这里测试的两倍,平均需要大约 0.6 毫秒。

作为旁注,使用上述 NEON 参数编译的第二个代码(展开和指针)花费的时间大致相同,为 0.6 毫秒。

关于c++ - 在 C++ 中复制跨步数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17090742/

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