QNX 平台下 mmap 缓存与非缓存模式的 memcpy 性能分析
文章目录
1. 引言
2. 为什么对比 Cache 与 NoCache?
3. mmap nocache 介绍
名词解释
示例代码
4. 实验数据对比
4.1 测试环境
4.2 测试设置
4.3 测试数据
4.4 代码示例
memcpy
invalidate memcpy
asm memcpy
5. 分析与结论
5.1 缓存场景下
5.2 非缓存场景下
5.3 总结
6. 附完整测试C++源码
1. 引言
在嵌入式系统中,数据处理效率直接影响系统性能。QNX 系统允许通过 mmap 将文件映射到内存,并可选择是否启用缓存。 本文对比缓存(Cache)和非缓存(NoCache)模式下 memcpy 与汇编版 asm_memcpy 的数据传输速率
2. 为什么对比 Cache 与 NoCache?
缓存可显著提升 CPU 访问频繁数据的速度,从而改善整体性能。但在实时性要求高或对数据一致性有严格要求的场景下,缓存可能引入同步问题或不必要的延迟,此时禁用缓存(NoCache)更为合适。
3. mmap nocache 介绍
在 QNX 中,mmap 可将文件或设备内存映射到进程地址空间。使用 MAP_NOCACHE 标志时,映射的内存页不进入文件系统缓存,直接与文件关联。这对于频繁读写大数据量的场景较为适用,因为它降低了缓存管理开销,提高了数据传输的实时性。
名词解释
mmap cached:使用 PROT_READ | PROT_WRITE 标志进行内存映射,内存页会进入文件系统缓存。
mmap nocached:使用 PROT_READ | PROT_WRITE | MAP_NOCACHE 标志进行映射,内存页不会被缓存。
示例代码
#include
#include
#include
int main() {
int fd = open("file.txt", O_RDWR);
char *ptr = mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOCACHE, fd, 0);
// 使用 ptr 直接读写文件数据
// ...
munmap(ptr, 100);
close(fd);
return 0;
}
4. 实验数据对比
4.1 测试环境
系统:QNX Neutrino RTOS 7.1
硬件:ARM Cortex-A53
4.2 测试设置
测试程序主要涉及以下几种操作:
mmap cached:启用缓存的内存映射。
mmap nocached:禁用缓存的内存映射。
memcpy:标准 C 的 memcpy。
invalidate memcpy:在 memcpy 前调用 msync 同步缓存。
asm memcpy:使用 ARM 汇编实现的内存快速拷贝。
4.3 测试数据
下表展示了不同情况下的内存拷贝速率(单位:MB/s):
测试场景
memcpy (cached)
memcpy (nocached)
invalidate memcpy (cached)
invalidate memcpy (nocached)
asm memcpy (cached)
asm memcpy (nocached)
速度 (MB/s)
2133.33
116.36
1333.33
112.28
2133.33
225.35
4.4 代码示例
memcpy
适用于大部分场景的标准内存拷贝操作。
for (size_t i = 0; i < count; i++) {
memcpy(dst, src[i], bytes);
}
invalidate memcpy
调用 msync 无效化共享内存后,再执行 memcpy 以确保数据一致性。
for (size_t i = 0; i < count; i++) {
msync(src[i], bytes, MS_INVALIDATE);
memcpy(dst, src[i], bytes);
}
asm memcpy
基于 ARM 汇编的优化实现,通过一次加载和存储 128 位数据(如 ldp、stp 指令),充分利用流水线和内存带宽以提升性能。
inline void aarch64_fast_memcpy(void *dst, const void *src, size_t size) {
#ifdef _QNX_
void *ss = (void *)src, *dd = (void *)dst;
size_t sz = size;
asm volatile("loop_start: "
"ldp q3, q4, [%0,#0x0]\n"
"ldp q5, q6, [%0,#0x20]\n"
"ldp q7, q8, [%0,#0x40]\n"
"ldp q9, q10,[%0,#0x60]\n"
"stp q3, q4, [%1,#0x0]\n"
"stp q5, q6, [%1,#0x20]\n"
"stp q7, q8, [%1,#0x40]\n"
"stp q9, q10,[%1,#0x60]\n"
"add %0, %0, #0x80\n"
"add %1, %1, #0x80\n"
"subs %2, %2, #0x80\n"
"b.ne loop_start\n"
"dsb sy\n"
:
: "r"