2.4 技巧24在GPU和Linux用户之间划分内存
你从树莓派获得的性能和你分配给它的核心组件的内存数量是紧密关联的,因为它不是一个你可以放入更多RAM的系统,因此你必须根据你的项目需要以最好的方式分配有效内存。
在嵌入式硬件的世界里,内存几乎总是一个珍贵而稀缺的东西。系统性能通常和存在的(以及可访问的)内存紧密关联。此外,大多数嵌入式系统并没有提供任何用户可以维护的方法来提高物理内存的大小,而树莓派并无不同。
当B型树莓派首次发布时,它自带了256MiB1内存(可能是Hynix MobileDDR2或Samsung Mobile DRAM,取决于其何时生产)。在BCM2835片上系统的内部,该内存在物理上被放置在博通公司的媒体处理器之上,这就是所谓的叠层封装(PoP,Package on Package)。PoP允许嵌入式系统将多个球栅阵列(BGA,ball grid array)封装在垂直堆叠上。
树莓派的片上系统使用了一个混合逻辑内存堆栈,这有助于节省空间,同时也可以允许硬件供应商有更广泛的兼容选项的选择余地(并帮助他们降低成本)。这个设计让他们可以轻松地将B型树莓派的板上内存从256Mib升级到512MiB(从2012年10月15日之后,所有买到的B型产品都有更大的内存)。
如何判断你的Pi的类型
如果你手头有个Pi有段时间了,而你不确定它是哪一种,那么你可以使用cat /proc/cpuinfo命令来了解。结果看上去像下面这样?
版本(Revision)后面的信息可以告诉你手头的是哪种主板。请参考此表:
这大大地提高了树莓派的性能,但不幸的是,更换成这种大小的内存的决定只是真正适用于制造的时候,而不适合用户来自己动手。堆叠这么小的BGA元器件最好是由机器,而不是由笨拙的人手来完成焊接。
即使是较新的512MiB的内存也是一个稀缺资源,因为BCM2835片上系统的工作方式,必须要留一些内存给GPU。你可能已经在x86计算机的低端显卡上看到过这种方式,这些显卡并没有配备专门的显卡内存,因此需要分配一些系统内存供GPU使用。树莓派固件允许你自己定制分配给GPU的内存数量。
在树莓派B型产品出现之前,分配自定义内存是通过选择start.elf文件来实现的。其分配方式如表2-1所示:
在B型树莓派固件只有一种可能的内存容量(256MiB)需要支持的时候,这种方法行之有效。不过当他们开始生产512MiB的B型产品时,这种方法就不再有意义。没有继续采用这种方式的另一个原因是,最显而易见的是在512MiB产品上将会产生两倍数量的可能的内存分配方式(即使其中一些相当可笑)。此外,他们还希望固件能够同时支持这两种产品,而划分内存的start.elf模式和256MiB容量的硬编码关联紧密。
2.4.1 使用config.txt文件分配内存
当前的固件(需要512MiB产品)放弃了独立的start.elf文件的方法,而添加了由start.elf从config.txt文件中读取变量(gpu_mem)的支持,该变量用来指定用户希望分配给GPU的内存容量,以16MiB的块为阶梯,16MiB最小,448MiB最大。
要设置这个变量,请在你常用的编辑器中打开config.txt文件(在包含树莓派Linux映像的SD卡的boot分区中),使用如下语法(此处的value为一整数值,表示分配给GPU的总MiB数,以16MiB的块为阶梯,从16到128Mib):
树莓派固件默认设置gpu_mem=64,但你到底需要分配多少内存给GPU?答案取决于你的树莓派将被用来做什么。
如果你将之用于headless模式(参见技巧11),你可以将gpu_mem设置为最小值16。如果你这么设置,你需要确保start_cd.elf和fixup_cd.elf这两个文件存在,因为它们将被替换使用。这么干的时候请务必小心,因为在最小设置时视频将不能工作,它将剩下的496MiB内存全部都留给ARM CPU使用了(这将被Linux的用户空间使用)。
gpu_mem=32是一个仅仅用于轻微视频友好的选项,Linux内核可以驱动1080p的帧缓冲,但是3D和视频进程将无法正常工作。在gpu_mem=128时,你将获得出色的3D和视频解码性能,但你留给Linux用户空间的只有384MiB内存了。
在分配256MiB/256MiB的道路上,你需要给GPU分配足够的内存来处理大型结构,但是这会使得Linux用户空间竞争更趋激烈。虽然GPU内存值可以增加到高达448MiB,但是我们一般不建议其超过128MiB,除非你有一个GPU非常密集使用的场景。
虽然核心Linux内核能够在内存饥渴的环境下运行,但大多数用户空间程序(特别是图形化程序)都需要几十MiB的内存才可以正常工作,而树莓派比大多数最流行的智能手机所拥有的内存都要少(例如,Galaxy Nexus和iPhone 5有1GiB内存,而Nexus 4有2GiB的内存)。
也请记住,Linux超前的预缓存中的可用内存当前并没有被应用程序使用来提高系统的性能,这意味着你分配给ARM CPU的内存越多,你从Linux中获得的性能就会越好。
制作兼容256MiB和512MiB型号的config.txt文件
有可能制作一个在256MiB和512MiB的B型树莓派上都可以工作的config.txt文件。要设置在两类产品上都兼容的GPU内存,你需要使用gpu_mem_256和gpu_mem_512参数。gpu_mem_256参数用于256MiB的B型树莓派,并覆盖掉gpu_mem中设置的任何值,而这个参数在512MiB树莓派B型中被完全忽略。
设置gpu_mem_512参数情况完全相同,除了它是被用在512MiB产品上并被256MiB产品忽略掉之外。gpu_mem_256最大值为192,gpu_mem_512的最大值为448。
在Raspbian上,也可以使用raspi-config工具来配置可视化的内存分配:以root用户启动raspi-config,并选择Memory Split选项。
对于本书中的大部分技巧和项目,gpu_mem=128应该是一个良好的开端。这个设置在我们的大多数项目中都有着最佳的综合性能。请随意尝试吧,你所能带来的唯一害处至多是树莓派的性能下降,况且你随时都可以将它改回来。
2.4.2 自动共享内存
虽然你也许能够预期你需要如何在CPU(操作系统)和GPU(图形)之间分配内存,但也有很多的情况下,你可能并不知道真实情况。这时,你真的希望树莓派可以根据CPU和GPU的需要而快速地划分并分配内存。
2012年11月之后的固件及3.6版本的Linux内核更新之后,有一个更好的方法来管理GPU/CPU内存分配,它被称为连续内存分配器(CMA,Contiguous Memory Allocator)。CMA能够通过设置GPU的低和高水平标记来动态管理GPU和ARM CPU之间的内存分配。
config.txt文件中对应GPU低水平标记的参数是cma_lwm,而cma_hwm是GPU高水平标记的参数。为了使用这些参数,你还需要在系统启动时传递一些选项给Linux内核。你可以在cmdline.txt文件(位于SD卡的boot分区中)中通过添加这些选项来做到这一点:
cmdline.txt文件的这个变化带来的副作用是禁用了树莓派中内嵌的以太网控制器的turbo模式,不过如果你没有一个网络密集型应用案例的话,你可能不必太在意这点。而且禁用turbo模式有时也可以提高无线网络的性能(并且在某些情况下可以消除系统日志中的许多调试(DEBUG)噪音)。
在此配置下,你还需要在config.txt文件中设置如下值:
一旦你做了这些设置并重启树莓派之后,其缺省会分配给Linux用户空间466 MiB可用内存(对于256 MiB的B型树莓派,这个值是212 MiB),并可以根据需要给GPU分配更多的内存(根据高低水平标记)。
虽然CMA支持是比较新的功能,我们仍然强烈建议你尝试它,而不是像大多数常见情况下的硬编码分配方式。它将提升像Web浏览器这样的应用的性能,同时仍然可以按照需求保持高GPU内存利用率。