填了几个坑之后,新的uboot可以启动到内核了,但发现启动速度非常慢,内核启动速度慢了接近10倍!明明是同一个内核,为什么差异这么大。
排查寄存器初步排查了下设备树配置,以及uboot跳转内核前的一些关键寄存器,确实在两个版本的uboot中有所不同,但具体去看这些不同,发现都不会影响速度,将一些驱动对齐之后寄存器差异基本就消失了。
差异的分界那再细看,kernel的速度有差异,uboot呢?在哪个时间点之后,速度开始产生差异?
尝试在两个版本的uboot中插入一些操作,对比时间戳,发现两个uboot在某个节点之后的速度确实有区别。
进一步排查,原来是在打开cache操作之后,旧uboot的速度就会比新uboot快。尝试将旧uboot的cache关掉,则二者基本一致。尝试将旧uboot操作cache的代码,移植到新uboot,未发生改变。
此时可确认新uboot的开cache有问题。但觉得这个跟kernel启动慢没关系。因为uboot进入kernel之前都会关cache,由kernel自己去重新打开。
也就是不管是用哪份uboot,也不管uboot中是否开了cache,对kernel阶段都应该没有影响才对。
于是记录下来uboot的这个问题,待后续修复。先继续找kernel启动慢的原因。(注:现在看来当时的做法是有问题的,这里的异常这么明显,应该设法追踪下去找出原因才对)
锁定ubootuboot的嫌疑非常大,但还不能完全确认,因为uboot之前还有一级spl。是否会是spl的问题呢?
尝试改用新spl+旧uboot,启动速度正常。而新spl+新uboot的启动速度则很慢,其他因素都不变,说明问题确实出在uboot阶段。
多做or少做当时到这一步就卡住了,直接比较两份uboot的代码不太现实,差异太大了。
后来我就给自己提了个问题,到底新uboot是多做了某件事情,还是少做了某件事情?
换个说法,目前已知
spl --> 旧uboot --> kernel(速度快) spl --> 新uboot --> kernel(速度快)但到底是以下的情况A还是情况B呢?
A: spl(速度慢) --> 旧uboot(做了某个会提升速度的操作) --> kernel(速度快) spl(速度慢) --> 新uboot(少做了某个会提升速度的操作) --> kernel(速度慢) B: spl(速度快) --> 旧uboot(没做特殊操作) --> kernel(速度快) spl(速度快) --> 新uboot(多做了某个会限制速度的操作) --> kernel(速度慢)为了验证,我决定让spl直接启动内核,看看内核到底是快是慢。
支持过程碰到了一些小问题
1.spl没有能力加载这么大的kernel
解决:此时不需要kernel能完全启动,只需要能加载启动一段,足以体现出启动速度是否正常即可,于是裁剪出一个非常小kernel来辅助实验。
2.kernel需要dtb
解决:内核有一个CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE选项。选上重新编译。编译后再用dd将kernel和dtb拼接到一起,作为新的kernel。这样,spl就只需要加载一个文件并跳转过去即可。
试验结果,spl启动的kernel和使用新uboot启动的kernel速度一致,均比旧uboot启动的kernel慢。
说明,旧uboot中做了某个关键操作,而新uboot没做。
找出关键操作那接下来的任务就是,找出旧uboot中的这个关键操作了。
怎么找呢?有了上一步的成果,我们可以使用以下方法来排查
spl加载kernel和旧uboot
spl跳转到旧uboot,此时kernel其实已经在dram中准备好了,随时可以启动
在旧uboot的启动流程各个阶段,尝试直接跳转到kernel,观察启动速度
如果在旧uboot的A点跳转kernel启动慢,B点跳转启动快,则说明关键操作位于AB点之间。