C++ 在C+中复制跨步数据+;
我有两个数组,我想把一个数组复制到另一个数组中。例如,我有C++ 在C+中复制跨步数据+;,c++,stride,C++,Stride,我有两个数组,我想把一个数组复制到另一个数组中。例如,我有 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 ... 从“”一文来看,C中似乎没有这种可能性 然而,我经历过,在某些情况下,memcpy比基于循环的拷贝的更快 我的问题是,;有没有办法有效地执行C++中的内存拷贝,至少作为标准 < < /COD>循环>? 多谢各位 编辑-澄清问题 为了使问题更清楚,让我们用a和b来表示手头的两个数
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 ...
从“”一文来看,C中似乎没有这种可能性
然而,我经历过,在某些情况下,memcpy
比基于循环的拷贝的更快
我的问题是,;有没有办法有效地执行C++中的内存拷贝,至少作为标准<代码> < < /COD>循环>?
多谢各位
编辑-澄清问题
为了使问题更清楚,让我们用a
和b
来表示手头的两个数组。我有一个函数,它为
循环执行以下唯一的
for (int i=0; i<NumElements, i++)
a_[i] = b_[i];
<> P>是否有任何方法有效地执行C++中的内存拷贝,至少作为循环的标准?
<> > >编辑2:在C++库中没有跨复制的函数。
由于跨步复制不像内存复制那样流行,芯片制造商和语言设计都专门支持跨步复制
假设对
循环使用标准的,则可以通过使用循环展开获得一些性能。有些编译器有展开循环的选项;这不是一个“标准”选项
为
循环提供标准的:
#define RESULT_SIZE 72
#define SIZE_A 48
#define SIZE_B 24
unsigned int A[SIZE_A];
unsigned int B[SIZE_B];
unsigned int result[RESULT_SIZE];
unsigned int index_a = 0;
unsigned int index_b = 0;
unsigned int index_result = 0;
for (index_result = 0; index_result < RESULT_SIZE;)
{
result[index_result++] = B[index_b++];
result[index_result++] = A[index_a++];
result[index_result++] = A[index_a++];
}
在展开版本中,循环的数量已减少一半
与其他选项相比,性能改进可能微不足道。
以下问题会影响性能,并且每个问题可能有不同的速度改进:
- 处理数据缓存未命中
- 指令管道的重新加载(取决于处理器)
- 操作系统用磁盘交换内存
- 同时运行的其他任务
- 并行处理(取决于处理器/平台)
并行处理的一个例子是让一个处理器将B项复制到新阵列,另一个处理器将A项复制到新阵列。可能是一个过于具体的答案,但在支持NEON的ARM平台上,可以使用NEON矢量化来加快复制速度。在资源相对有限的环境中,这可能是拯救生命的方法,这可能就是为什么首先在该环境中使用ARM的原因。一个突出的例子是Android,其中大多数设备仍然使用支持NEON的ARMV7A架构
以下示例演示了这一点,它是一个将YUV420sp图像的半平面UV平面复制到YUV420p图像的平面UV平面的循环。源缓冲区和目标缓冲区的大小都是640*480/2
字节。所有示例都是在androidndkr9d中使用g++4.8编译的。它们在三星Exynos Octa 5420处理器上执行:
一级:常规
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.15毫秒。根据另一个答案,这可能与在常规体系结构上的速度一样快
第3级:常规+GCC自动霓虹灯矢量化
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];
}
}
void convertUVsp2UVp(
无符号字符*,
无符号字符*uu限制dstptr,
int(步幅)
{
对于(int i=0;iA standard for loop的执行速度至少与standard for loop一样快……讽刺的是,这取决于您使用的数据存储结构。对于阵列,我认为您不能比按模数递增的for loop做得更好。memcpy
有时比for
循环更快,因为它可以执行优化因为它运行的内存是连续的。这些优化不能在这里进行。@daupick但是为什么CUDA有cudaMemcpy2D
用螺距复制?@JackOLantern:CUDA并行运行。@JackOLantern因为cudaMemcpy2D
在安装在设备上的GPU上并行执行,而memcpy
在上执行设备本身。谢谢你友好的回答。我已经编辑了我的帖子,以便更好地解释这个问题。你认为通过#pragma unroll
我有机会改善这种情况吗?我不知道,因为关于副本的一切都是在运行时知道的。正如我所说,这取决于处理器。对于某些处理器,分支刷新指令离子管道和处理器必须重新加载。一些现代处理器有足够的指令管道缓存,它们在指令缓存中保留一个简单的for循环,而不必重新加载。大多数处理器更喜欢执行顺序指令,也不喜欢遇到分支指令。我的首选是不要使用编译器pragma
但是可以展开循环。这允许更多的可移植代码,我可以控制内容的多样性。在我的工作中,我展开了一个循环,它处理32个插槽的FIFO,使用32个独立语句;工作非常快。我理解你的观点,pragma
可以引入代码可移植性问题,但一般来说我不知道UCH关于< <代码> > <代码>循环,因此我不能手动执行循环展开。请您编辑您的帖子,提供一个简短的、明确的声明,没有“内置”C++功能来执行跨步副本,这样我就可以接受您的答案了吗?谢谢。
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];
}
}
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;
}
}
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];
}
}