最终的 ARM Linux 内存碎片与 NEON Copy 但不是 memcpy
Posted
技术标签:
【中文标题】最终的 ARM Linux 内存碎片与 NEON Copy 但不是 memcpy【英文标题】:Eventual ARM Linux Memory Fragmentation with NEON Copy but not memcpy 【发布时间】:2018-04-11 16:48:43 【问题描述】:我在 BeagleBone X-15 (ARM Cortex-A15) 板上运行 Linux 4.4。我的应用程序映射 SGX GPU 的输出,需要复制 DRM 后备存储。
memcpy 和我的自定义 NEON 复制代码都可以工作...但是 NEON 代码要快得多(~11ms vs. ~35ms)。
我注意到,相当一致地,在 12500 秒后,当我使用 NEON 版本的副本时,Linux 会因内存不足 (OOM) 而终止应用程序。当我运行应用程序并将一行从 NEON 副本更改为标准 memcpy 时,它会无限期地运行(到目前为止 12 小时......)。但是复制比较慢。
我在下面粘贴了 mmap、copy 和 NEON 复制代码。我的 NEON 副本真的有问题吗?谢谢。
霓虹灯复制:
/**
* CompOpenGL neonCopyRGBAtoRGBA()
* Purpose: neonCopyRGBAtoRGBA - Software NEON copy
*
* @param src - Source buffer
* @param dst - Destination buffer
* @param numpix - Number of pixels to convert
*/
__attribute__((noinline)) void CompOpenGL::neonCopyRGBAtoRGBA(unsigned char* src, unsigned char* dst, int numPix)
(void)src;
(void)dst;
(void)numPix;
// This case takes RGBA -> BGRA
__asm__ volatile(
"mov r3, r3, lsr #3\n" /* Divide number of pixels by 8 because we process them 8 at a time */
"loopRGBACopy:\n"
"vld4.8 d0-d3, [r1]!\n" /* Load 8 pixels into d0 through d2. d0 = R[0-7], d1 = G[0-7], d2 = B[0-7], d3 = A[0-7] */
"subs r3, r3, #1\n" /* Decrement the loop counter */
"vst4.8 d0-d3, [r2]!\n" /* Store the RGBA into destination 8 pixels at a time */
"bgt loopRGBACopy\n"
"bx lr\n"
);
在这里Mmap和复制代码:
union gbm_bo_handle handleUnion = gbm_bo_get_handle(m_Fb->bo);
struct drm_omap_gem_info gemInfo;
char *gpuMmapFrame = NULL;
gemInfo.handle = handleUnion.s32;
int ret = drmCommandWriteRead(m_DRMController->m_Fd, DRM_OMAP_GEM_INFO,&gemInfo, sizeof(gemInfo));
if (ret)
qDebug() << "Cannot set write/read";
else
// Mmap the frame
gpuMmapFrame = (char *)mmap(0, gemInfo.size, PROT_READ | PROT_WRITE, MAP_SHARED,m_DRMController->m_Fd, gemInfo.offset);
if ( gpuMmapFrame != MAP_FAILED )
QElapsedTimer timer;
timer.restart();
//m_OGLController->neonCopyRGBAtoRGBA((uchar*)gpuMmapFrame, (uchar*)m_cpyFrame,dmaBuf.width * dmaBuf.height);
memcpy(m_cpyFrame,gpuMmapFrame,dmaBuf.height * dmaBuf.width * 4);
qDebug() << "Copy Performance: " << timer.elapsed();
【问题讨论】:
寄存器从'R0'传递过来;我猜你有一个 C++ 的“this”。您的霓虹灯组装器可能是错误的。使用输入/输出说明符来告诉编译器你在做什么,并做这个错误证明,不需要 (void) casts 和 'noinline'。不知道编译试图做什么(给定您设置的编译选项),因为您的汇编代码没有提示它正在发生什么。此外,您的“bx lr”将否定任何可能溢出堆栈的编译尾声。尝试让它与输入/输出参数一起编译,你会避免沮丧。 与memcpy()
相比,NEON 代码不会导致碎片化的直接影响。这是汇编器和编译器之间的某种接口错误。使用 neonCopyRGBAtoRGBA
尝试 objdump -S 以查看编译是否围绕您的内联汇编程序进行。
【参考方案1】:
好消息是,如果您将 vld4/vst4
替换为 vld1/vst1
,您的函数将运行得更快。
坏消息是您必须报告您使用和修改了哪些寄存器,包括CPSR
和内存,并且您不应该从内联汇编返回。 (bx lr
)。
__asm__ volatile(
"mov r3, r3, lsr #3\n" /* Divide number of pixels by 8 because we process them 8 at a time */
"loopRGBACopy:\n"
"vld1.8 d0-d3, [r1]!\n" /* Load 8 pixels into d0 through d2. d0 = R[0-7], d1 = G[0-7], d2 = B[0-7], d3 = A[0-7] */
"subs r3, r3, #1\n" /* Decrement the loop counter */
"vst1.8 d0-d3, [r2]!\n" /* Store the RGBA into destination 8 pixels at a time */
"bgt loopRGBACopy\n"
::: "r1", "r2", "r3", "d0", "d1", "d2", "d3", "cc", "memory"
);
http://www.ethernut.de/en/documents/arm-inline-asm.html
【讨论】:
以上是关于最终的 ARM Linux 内存碎片与 NEON Copy 但不是 memcpy的主要内容,如果未能解决你的问题,请参考以下文章
ARM NEON:由于内存访问带宽有限而预测性能问题的工具?
原创Linux内存管理 - zoned page frame allocator - 4