我想使用增强的REP MOVSB(ERMSB)为自定义获得高带宽memcpy.
ERMSB引入了Ivy Bridge微体系结构.如果您不知道ERMSB是什么,请参阅英特尔优化手册中的"增强型REP MOVSB和STOSB操作(ERMSB)" 部分.
我知道直接执行此操作的唯一方法是使用内联汇编.我从https://groups.google.com/forum/#!topic/gnu.gcc.help/-Bmlm_EG_fE获得了以下功能
static inline void *__movsb(void *d, const void *s, size_t n) {
asm volatile ("rep movsb"
: "=D" (d),
"=S" (s),
"=c" (n)
: "0" (d),
"1" (s),
"2" (n)
: "memory");
return d;
}
Run Code Online (Sandbox Code Playgroud)
然而,当我使用它时,带宽远小于memcpy.
使用我的i7-6700HQ(Skylake)系统,Ubuntu 16.10,DDR4 @ 2400 MHz双通道32 GB,GCC 6.2,__movsb获得15 GB/s并memcpy获得26 GB/s.
为什么带宽如此低REP MOVSB?我该怎么做才能改善它?
这是我用来测试它的代码.
//gcc -O3 -march=native -fopenmp foo.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include …Run Code Online (Sandbox Code Playgroud) 我在C中进行图像处理,需要在内存周围复制大块数据 - 源和目标永远不会重叠.
使用GCC(其中SSE,SSE2但不是SSE3可用)在x86平台上执行此操作的绝对最快方法是什么?
我希望解决方案可以是汇编还是使用GCC内在函数?
我发现下面的链接,但不知道它是否去了解它的最佳方式(笔者也表示有一些错误):http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm. 86/2006-02/msg00123.html
编辑:请注意,副本是必要的,我无法复制数据(我可以解释为什么,但我会饶你解释:))
我有一些代码,我经常复制一大块内存,通常只需要对它进行非常小的更改.
我已经实现了一个跟踪更改的系统,但我认为如果可能的话,可以告诉操作系统对内存进行"写时复制",并让它只处理那些部分的副本哪个改变了.然而,虽然Linux执行copy-on-write,例如fork()时,我找不到一种控制它并自己动手的方法.
在查看x86/x64架构中的寄存器表之后,我注意到有128,256和512位寄存器的整个部分,我从未见过它们用于汇编或反编译的C/C++代码: XMM(0-15)表示128,YMM(0-15)表示256,ZMM(0-31)512.
做了一些挖后我所收集的是,你必须使用2个64位操作,以一个128位的数字进行的,而不是使用通用的数学,add,sub,mul,div操作.如果是这种情况,那么具有这些扩展寄存器集的用途究竟是什么,是否有任何汇编操作可以用来操作它们?
我有一段代码是在x86处理器上运行的C ++应用程序的瓶颈,其中我们从两个数组中获取双精度值,强制转换为float并存储在结构数组中。这是瓶颈的原因是它被称为具有非常大的循环或数千次。
是否有使用SIMD Intrinsics进行复制和转换操作的更快方法?我已经在更快的memcpy上看到了这个答案,但没有解决演员表问题。
简单的C ++循环情况如下所示
int _iNum;
const unsigned int _uiDefaultOffset; // a constant
double * pInputValues1; // array of double values, count = _iNum;
double * pInputValues2;
MyStruct * pOutput; // array of outputs defined as
// struct MyStruct
// {
// float O1;
// float O2;
// unsigned int Offset;
// };
for (int i = 0; i < _iNum; ++i)
{
_pPoints[i].O1 = static_cast<float>(pInputValues1[i]);
_pPoints[i].O2 = static_cast<float>(pInputValues2[i]);
_pPoints[i].Offset = _uiDefaultOffset;
}
Run Code Online (Sandbox Code Playgroud)
注意: …
考虑以下函数accept,该函数采用类型的"通用引用" T并将其转发给具有parse<T>()lvalues重载和rvalues重载的函数对象:
template<class T>
void accept(T&& arg)
{
parse<T>()(std::forward<T>(arg), 0); // copy or move, depending on rvaluedness of arg
}
template<class T>
class parse
{
// parse will modify a local copy or move of its input parameter
void operator()(T const& arg, int n) const { /* optimized for lvalues */ }
void operator()(T&& arg) , int n) const { /* optimized for rvalues */ }
};
Run Code Online (Sandbox Code Playgroud)
由于完美转发使源对象处于有效但未定义的状态,因此无法在同一范围内再次完美转发.下面我尝试在一个假设的split()函数中尽可能少地复制一个int代表必须对输入数据进行的数字传递:
template<class T>
void …Run Code Online (Sandbox Code Playgroud) c++ rvalue-reference move-semantics perfect-forwarding c++11