用 neon 内部函数替换 memcpy

Posted

技术标签:

【中文标题】用 neon 内部函数替换 memcpy【英文标题】:Replacing memcpy with neon intrinsics 【发布时间】:2015-05-07 16:58:23 【问题描述】:

我试图通过编写相同的霓虹内在函数来击败“memcpy”函数。以下是我的逻辑:

uint8_t* m_input;  //Size as 400 x300
uint8_t* m_output; //Size as 400 x300
//not mentioning the complete code base for memory creat 

memcpy(m_output, m_input, sizeof(m_output[0]) * 300* 400);

霓虹灯:

int32_t ht_index,wd_index;
uint8x16_t vector8x16_image;

for(int32_t htI =0;htI < m_roiHeight;htI++)
    ht_index = htI * m_roiWidth ;

    for(int32_t wdI = 0;wdI < m_roiWidth;wdI+=16)
        wd_index = ht_index + wdI;
        vector8x16_image = vld1q_u8(m_input);

        vst1q_u8(&m_output[wd_index],vector8x16_image);
    

我在 imx6 硬件上多次验证了这些结果。

结果:

Memcpy :0.039 milisec
neon memcpy: 0.02841 milisec

我在某处读到,如果没有预先加载的指令,我们无法击败 MEMCPY。

如果是真的,那么我的代码是如何给出这些结果的。 是对还是错

【问题讨论】:

我想知道您选择的编译器供应商是否还没有为您提供特定于您的平台的专门版本的 memcpy。另外,是的,如果您在网上搜索任何时间,您应该会找到正确使用 PLD 来加快速度的 ARM memcpy() 函数。 阅读“每个程序员应该了解的关于内存的知识”(免费提供),了解如何科学地完成这些类型的测试。跳过部分太深,查看图表并尝试模仿它们。稍后,您将加深对该主题的理解,并可以阅读更深入的部分。 【参考方案1】:

如果编写正确,非 NEON memcpy() 应该能够使您设备上的 L3 带宽饱和,但对于较小的传输(完全适合 L1 或 L2 缓存)情况可能会有所不同。您的测试可能适合 L2 缓存。

不幸的是,memcpy 必须适用于任何大小的调用,因此它无法合理地优化缓存内和缓存外的情况,同时优化非常短的副本,其中检测哪种类型的成本优化的最好结果是主导因素。

即便如此,您的测试也可能不公平。您必须确保两种实现都不受不同的缓存前提条件或不同的虚拟页面布局的影响。

确保两个测试都不完全在另一个之前运行。测试一些实现,然后测试其他一些,然后回到第一个和第二个几次,以确保它们不受任何预热条件的影响。并为两者使用相同的缓冲区,以确保您的虚拟地址空间的不同部分不存在只会损害一种实现的特征。

此外,有些情况您的memcpy 无法处理,但这些对于大额转账应该没有太大影响。

【讨论】:

以上是关于用 neon 内部函数替换 memcpy的主要内容,如果未能解决你的问题,请参考以下文章

使用 ARM neon 内部函数进行深度转换

将 SSE2 迁移到 Arm NEON 内部函数

ARM NEON 内部函数将 D(64 位)寄存器转换为 Q(128 位)寄存器的低半部分,而上半部分未定义

memcpy 的内部实现是如何工作的?

使用 ARM NEON 执行比 C 代码需要更长的时间

用于 C++/SSE 代码的高效 NEON 内在函数