交换两个大小相等的非重叠内存区域的最快方法是什么?比方说,我需要用(t_Some *b)交换(t_Some *a)。考虑到时空权衡,增加临时空间会提高速度吗?例如,(char *tmp)与(int *tmp)?我正在寻找一种便携解决方案。
原型:
void swap_elements_of_array(void* base, size_t size_of_element, int a, int b);发布于 2011-11-17 19:57:10
最好的办法是最大限度地使用寄存器,这样在读取临时数据时,就不会出现额外的(可能是缓存的)内存访问。寄存器的数量将取决于系统,寄存器分配(将变量映射到实际寄存器的逻辑)将取决于编译器。所以你最好的选择是,我想只需要一个寄存器,并且它的大小和指针一样。这归结为一个简单的for循环,它处理被解释为size_t数组的块。
发布于 2018-02-16 08:05:48
移动内存块的最快方法是使用<string.h>中的memcpy()。如果您从a memcpy()到temp,从b到a执行memmove(),然后从temp执行memcpy()到b,那么将有一个使用优化库例程的交换,编译器可能会内联这些库例程。您不希望一次复制整个块,而是以向量大小的块为单位。
在实践中,如果您编写了一个紧凑的循环,编译器可能会知道您正在交换数组的每个元素,并相应地进行优化。在大多数现代CPU上,您希望生成向量指令。如果您确保所有三个缓冲区都对齐,它可能会生成更快的代码。
然而,您真正想要做的是让优化器的工作变得更容易。以这个程序为例:
#include <stddef.h>
void swap_blocks_with_loop( void* const a, void* const b, const size_t n )
{
unsigned char* p;
unsigned char* q;
unsigned char* const sentry = (unsigned char*)a + n;
for ( p = a, q = b; p < sentry; ++p, ++q ) {
const unsigned char t = *p;
*p = *q;
*q = t;
}
}如果你把它翻译成字面上写的机器代码,这是一个糟糕的算法,一次复制一个字节,每次迭代进行两次递增,等等。但在实践中,编译器会看到您真正想要做的事情。
在带有-std=c11 -O3的clang 5.0.1中,它在x86_64上产生(部分)以下内循环:
.LBB0_7: # =>This Inner Loop Header: Depth=1
movups (%rcx,%rax), %xmm0
movups 16(%rcx,%rax), %xmm1
movups (%rdx,%rax), %xmm2
movups 16(%rdx,%rax), %xmm3
movups %xmm2, (%rcx,%rax)
movups %xmm3, 16(%rcx,%rax)
movups %xmm0, (%rdx,%rax)
movups %xmm1, 16(%rdx,%rax)
movups 32(%rcx,%rax), %xmm0
movups 48(%rcx,%rax), %xmm1
movups 32(%rdx,%rax), %xmm2
movups 48(%rdx,%rax), %xmm3
movups %xmm2, 32(%rcx,%rax)
movups %xmm3, 48(%rcx,%rax)
movups %xmm0, 32(%rdx,%rax)
movups %xmm1, 48(%rdx,%rax)
addq $64, %rax
addq $2, %rsi
jne .LBB0_7而具有相同标志的gcc 7.2.0也进行了矢量化,更少地展开循环:
.L7:
movdqa (%rcx,%rax), %xmm0
addq $1, %r9
movdqu (%rdx,%rax), %xmm1
movaps %xmm1, (%rcx,%rax)
movups %xmm0, (%rdx,%rax)
addq $16, %rax
cmpq %r9, %rbx
ja .L7说服编译器生成一次只处理一个单词的指令,而不是向量化循环,这与您想要的相反!
发布于 2016-02-24 00:48:14
Word写入将是最快的。但是,块大小和对齐都需要考虑。在实践中,事情通常是明智地对齐的,但你不应该指望它。memcpy()可以安全地处理所有事情,并且可以在合理的范围内针对固定大小进行专用(内置)。
这是一个可移植的解决方案,在大多数情况下都工作得相当好。
static void swap_byte(void* a, void* b, size_t count)
{
char* x = (char*) a;
char* y = (char*) b;
while (count--) {
char t = *x; *x = *y; *y = t;
x += 1;
y += 1;
}
}
static void swap_word(void* a, void* b, size_t count)
{
char* x = (char*) a;
char* y = (char*) b;
long t[1];
while (count--) {
memcpy(t, x, sizeof(long));
memcpy(x, y, sizeof(long));
memcpy(y, t, sizeof(long));
x += sizeof(long);
y += sizeof(long);
}
}
void memswap(void* a, void* b, size_t size)
{
size_t words = size / sizeof(long);
size_t bytes = size % sizeof(long);
swap_word(a, b, words);
a = (char*) a + words * sizeof(long);
b = (char*) b + words * sizeof(long);
swap_byte(a, b, bytes);
}https://stackoverflow.com/questions/8166502
复制相似问题