Linux嵌入式系统(ARM架构)中的内存吞吐量低

3
我正在使用ARM926EJS。在无Linux的情况下(仅作为入门可执行文件),我在内存复制测试中获得了20%以上的内存速度。但在Linux中,相同的代码运行要慢20%。
以下是代码:
``` /// 以下代码只执行突发模式memcopy测试。 void asmcpy(void *a, void *b, int iSize) { do { asm volatile ( "ldmia %0!, {r3-r10} \n\t" "stmia %0!, {r3-r10} \n\t" :"+r"(a), "+r"(b) : :"r"(r3),"r"(r4),"r"(r5),"r"(r6),"r"(r7),"r"(r8),"r"(r9),"r"(r10) ); }while(size--) } ```
我验证了在Linux中没有其他进程占用CPU时间。(我使用time命令检查了这一点,它显示“real time”与“usr time”相同)
请告诉我Linux可能有什么问题?
谢谢和问候。
附加:
我的测试代码是:
``` int main() { int a[320 * 120], b[320 * 120];
for(int i=0; i != 10000; i++) { /// Size is divided by 8 because our memcpy function performs 8 integer load stores in the iteration asmcpy(a, b, (320 * 120) / 8); } } ```
Getting Started可执行文件是一个bin文件,通过串口发送到RAM中并直接通过跳转到该RAM地址执行。(无需操作系统)
补充:
我没有在其他处理器上看到这样的性能差异。它们使用SD RAM,而此处理器使用DDR Ram。可能是原因吗?
补充: 入门代码未启用数据缓存,而Linux模式下启用了数据缓存,因此理论上所有数据都应被缓存且无需任何RAM延迟进行访问,但Linux仍慢20%。
补充: 我的微控制器是LPC3250。两个测试都在同一外部DDR RAM上进行了测试。

1
你能否在两个不同的设置上发布你的测试代码和场景?另外,什么是“入门可执行文件”?总体上再多解释一点,可能有很多不同的原因。 - ThePosey
1
这里进行的性能比较几乎是不可比较的,因为你正在运行一个完整的操作系统,其中包括定时器滴答声、内存管理等,所有这些都被安排运行,而没有操作系统只是直接运行指令。我认为这基本上解释了你的性能差异。就像Javier所说的,即使没有其他用户进程在运行,内核仍然会自己做很多事情。 - ThePosey
我有类似的硬件(ARM926EJS + DDR),但我观察到相反的情况:如果没有操作系统,内存操作非常缓慢,直到缓存被激活(即在操作系统中)。 - shodanex
使用Burst Mode RAM访问,就像我正在做的那样,使用LDMIA和STMIA来提高速度。 - SunnyShah
4个回答

10

这款芯片具备MMU功能,所以Linux很可能正在使用它来管理内存。也许仅开启它就会带来一些性能损失。此外,Linux采用延迟内存分配策略,只有在进程首次访问时才分配内存页面。如果你正在复制一个大块内存,则在循环过程中,MMU将生成页面错误以请求内核分配页面。 在低端处理器上,所有这些上下文切换都会导致缓存刷新,并引入明显的减速。

如果您的系统小到足够使用无MMU版本的Linux(如uClinux),那么也许可以使用更便宜但性能相似的芯片。在嵌入式系统中,每一分钱都很重要。

更新:一些额外细节:

每个Linux进程都有自己的内存映射,最初只包括内核和(可能是)可执行代码。剩余的线性4GB(32位)似乎是可用的,但没有RAM页面分配给它们。一旦您读取或写入未分配的内存地址,MMU就会发出页面错误并切换到内核。内核发现仍有大量可用的RAM页面,因此选择一个,将其分配给出错点并返回您的代码,以完成中断的指令。下一个指令不会失败,因为整个页面(通常为4KB)已经分配;但是几次迭代后,它将再次碰到未分配的空间,并且MMU将再次调用内核。


嗨,Javier,我只是在RAM之间进行mem copy。那么页面错误如何发生?我使用分配在堆栈上的153KB内存进行memcopy。我将其循环运行10,000次。 - SunnyShah
所有的RAM都是由内存管理的,因此随时可能发生故障。请查看更新。 - Javier
1
嗯... 300KB 只是几页纸的大小,而且在第一页之后,所有空间都应该被映射,所以你不应该再遇到页面错误。如上所述,一些简单的内存管理单元会在处理流程中引入另一个步骤,并可能影响性能,即使它们不再生成页面错误也是如此。 - Javier
4
即使你说“没有其他进程在消耗CPU时间”,系统总会有定时器中断和一些内核线程在运行。查看/proc/<pid>/stat文件可以了解时间都用在哪些地方了。请注意,这里的翻译保持了原文的意思和语气,同时尽可能简洁易懂。 - Javier

3

你是如何进行时间测量的?你的示例中没有时间代码。

你确定你没有测量进程的加载/卸载时间吗?

两种情况下处理器时钟速度相同吗?

如果使用外部SDRAM,两种情况下RAM时序是否相同?

两种情况下数据缓存是否启用?

克利福德


“time”系统命令返回的数字正确吗?它可能被配置错误。当您遇到此类奇怪的结果时,一个好的选择是让程序按照其计时器每隔一分钟打印出几个东西,并使用物理时钟(或秒表)计时。 - Brooks Moses
数据缓存在开始模式下被禁用。将使用计时器并让您知道,谢谢。 - SunnyShah

2
开始并不是“只有一个可执行文件”。必须有一些代码来设置DDR控制器寄存器。
如果启用了缓存,那么MMU也必须启用。我认为在ARM926EJS上,你不能没有MMU而使用数据缓存。
我相信每次上下文切换都会导致缓存清除,因为缓存是虚拟索引、虚拟标记的,并且内核空间和用户空间不共享相同的地址空间,所以在与操作系统相比,可能会有更多不必要的缓存清除。
这里有一篇关于运行Linux时VIVT缓存清除成本的一些方面的论文

1
你使用的是哪种微控制器(不仅仅是ARM CPU)?
在非Linux运行时,你测试的数组是否可能是存储在微控制器设备本身的RAM中,而在Linux测试中,被测试的数组是否存储在外部RAM中?内部RAM通常比外部RAM访问速度更快 - 即使仅为Linux运行启用数据缓存,这也可能解释了Linux测试较慢的原因。

嗨,迈克尔,我的微控制器是LPC3250。这两个数据都在同一个外部DDR RAM上进行了测试。 - SunnyShah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接