多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

全志T113-i嵌入式Linux快速启动优化:从8.65秒到2.4秒

全志T113-i嵌入式Linux快速启动优化:从8.65秒到2.4秒 做带屏嵌入式产品的人应该都有过这种经历样机送到客户手里按下电源键黑屏等了三五秒LOGO才出来客户第一句往往是“这机器是不是坏了”。我自己在基于全志T113-i的HMI项目上就栽过这个跟头默认SDK编译出来的固件从上电到Qt界面完全可用实测8.65秒。对一台工业控制设备来说8秒听起来不算长但如果产线上每天过几千台机器每台的启动确认时间都压在这8秒里节拍根本走不起来。所以这个项目立项时给了一个硬指标从按下电源到UI完成首帧渲染2.5秒以内。整个优化链路从U-Boot裁剪一路做到Qt/LVGL应用层中间踩了不少坑也摸出了一些可复用的方法。这篇文章就把过程中的取舍、参数、时间账完整记录下来适合正在给全志T113-i或其他Cortex-A7平台做快速启动优化的朋友参考。1. 2.5秒的目标是怎么拆出来的1.1 带屏设备凭什么要在意启动时间很多人觉得嵌入式设备开机慢一点无所谓的设备又不是手机用户不会天天重启。但实际场景里启动时间直接影响的是产品验收和运营效率。拿我们做的HMI设备来说客户产线上每台设备在烧录完固件之后都要做一次开机自检确认屏幕能亮、触摸能点、界面能进然后再封箱出货。如果每次开机都要等接近9秒一天几千台机器光等待时间就多出好几个小时客户是会把这个问题写进验收报告的。除了产线效率终端用户的体验也很直接。楼宇对讲、车载仪表、充电桩屏幕这类设备用户按下电源之后盯着黑屏超过2秒就会开始怀疑设备坏了。我接触过的很多项目客户对启动时间的预期已经从“10秒内能接受”变成了“3秒内必须见到画面”这不是吹毛求疵而是行业里已经有人做到了。1.2 全志T113-i启动链路的时间账单T113-i是全志旗下一款面向工业级带屏应用的SoC双核Cortex-A7加一颗RISC-V协处理器集成度高成本控制好所以在HMI、楼宇对讲、智能门禁、车载仪表这类产品里出现频率很高。它的启动链路和大多数全志平台一样严格按照内部BROM到SPL再到U-Boot再到内核最后到用户空间的顺序执行内部BROM芯片出厂固化负责从启动介质读取SPL这段代码你碰不了。SPLSecondary Program Loader全志平台上也常叫boot0运行在SRAM里负责DDR初始化并把U-Boot主程序加载到DDR。U-Boot主程序负责加载内核、设备树、initramfs或者根文件系统。Kernel初始化驱动、挂载根文件系统、启动第一个用户进程。用户空间执行init脚本拉起Qt或者LVGL应用完成首帧渲染。这个链路每一段都有固定的时间开销。我们拿SDK默认固件在eMMC配置上实测得到了一张启动时间账单启动阶段默认耗时主要开销来源Boot ROM SPL0.65s启动介质读取、DDR初始化U-Boot主程序1.10s命令解析、串口打印、文件系统扫描Kernel initramfs2.40s驱动初始化、内核解压、printk输出rootfs与Qt应用4.50sinit脚本串行执行、Qt插件扫描、字体数据库构建四段加起来8.65秒离2.5秒的目标差了将近6秒。把目标拆解到每个阶段之后思路就清晰了SPL和U-Boot合计要压到0.7秒以内内核加initramfs要压到1秒以内应用层首帧要压到0.9秒以内。每个阶段省一点叠起来才能达标。2. SPL与U-Boot裁剪前半段能省多少2.1 SPL阶段可动手的空间全志平台的启动第一阶段是芯片内部BROM这一段没得改。能动手的是BROM从eMMC、SD或NAND读取SPL的过程。第一启动介质的选择对SPL加载时间影响很大。用eMMC的高速模式比如HS200和普通SD卡相比BROM读取SPL的时间差距在100到200毫秒。如果产品结构允许尽量用eMMC做主存储启动速度上的优势非常明显。项目里最终方案就是用eMMCSPL加载从0.4秒左右降到了0.2秒出头。第二SPL镜像的大小。BROM读取SPL时是按固定扇区数量读的如果把SPL镜像控制在更少的扇区内读的时间会相应减少。这个收益通常只有几十毫秒但不需要额外成本裁剪SPL里的调试代码就能做到。第三DDR初始化是SPL阶段最大的时间开销。全志SDK里DDR初始化包含时钟配置、时序参数、训练步骤某些配置项有“快速模式”或者可选的训练开关。这里我栽过一次跟头后面踩坑部分细说。一句话结论不要为了省时间盲目调整DDR频率和时序参数稳定性比这点毫秒值钱得多。2.2 U-Boot主程序的配置裁剪U-Boot阶段默认的耗时大头往往不是加载内核本身而是串口输出、命令解析和文件系统扫描。115200波特率下一个字符大约要87微秒U-Boot启动时如果刷出几百个字符光串口打印就能占到30到50毫秒。要是console配置不当U-Boot还会在多个存储设备之间扫描找可用的启动分区这个探测过程轻松吃掉一两百毫秒。我在这块实际裁剪的配置项如下配置项默认值改为收益说明CONFIG_BOOTDELAY1或30不等按键输入直接启动CONFIG_CMDLINE_EDITINGyn去掉命令行编辑功能CONFIG_CMD_USByn去掉USB命令减小镜像CONFIG_CMD_NETyn去掉网络命令CONFIG_DISPLAY_CPUINFOyn去掉CPU信息打印CONFIG_SILENT_CONSOLEny静默控制台无串口输出CONFIG_CMD_FATyn不用FAT文件系统时关闭关键点是CONFIG_SILENT_CONSOLE。把U-Boot控制台静默之后启动日志不再刷屏视觉上干净时间上也省得实实在在。U-Boot里还可以把CONFIG_SYS_PROMPT改短虽然只是减少几个字符的打印量但积少成多。2.3 bootcmd的直读改造U-Boot默认的bootcmd通常长这样load mmc 0:1 0x42000000 uImage load mmc 0:1 0x43000000 sunxi.dtb bootm 0x42000000 - 0x43000000这看起来很合理但load命令要解析FAT或ext4文件系统找出文件目录、读取文件头、逐块搬运。文件系统解析本身就带几十到上百毫秒开销。更快的做法是把内核和设备树放在裸分区或固定扇区用mmc read直接按扇区读取mmc read 0x42000000 0x1000 0x4000 mmc read 0x43000000 0x5000 0x1000 bootz 0x42000000 - 0x43000000这里的0x1000和0x4000是内核镜像所在的分区起始扇区和长度0x5000是设备树所在扇区。用raw read绕开文件系统后U-Boot加载内核的过程从150毫秒左右降到了50毫秒以内。bootargs也要精简。多余的mem、多个console参数传给内核后内核要解析并处理多做的printk和内存重映射都会增加启动时间。我们最终的内核命令行非常短consolettyS0,115200 loglevel3 rootwait init/sbin/init如果你连串口调试都不需要console可以直接去掉。2.4 要不要跳过完整U-Boot直接进内核U-Boot在快速启动这条路上还可以走更极端的一步跳过完整的U-Boot主程序让SPL直接加载内核。全志平台是有类似“SPL direct boot”的玩法的省掉U-Boot主程序那0.3到0.5秒非常可观。但我不建议在T113-i上这么做。SPL本身是一个“尽可能精简”的加载器它没有完整的设备树解析、没有环境变量机制、没有启动参数拼接逻辑这些工作全部要自己补。省下0.4秒增加的是成倍的调试难度。如果产品不是百万级量产且启动时间必须卡在1.5秒以内双阶段方案已经够用没必要去啃这块硬骨头。3. 内核与根文件系统把准备阶段压到1秒以内3.1 内核配置裁剪与压缩策略Linux内核启动时间的优化最直接的手段就是减少它要做的事情。T113-i的SDK默认内核配置非常全WiFi、蓝牙、声卡、HDMI、摄像头、网卡驱动全开着即使板子上根本没有这些外设内核也会在初始化阶段尝试probe这些驱动的设备树节点没有匹配设备时虽然跳过但解析和匹配的过程是实打实消耗时间的。我把内核配置做了一轮瘦身方向很明确板子上有哪些外设就保留哪些驱动其余全部关闭。关闭声卡、HDMI、摄像头、WiFi/BT、Ethernet相关驱动关闭不需要的文件系统exFAT、NTFS、F2FS等全部关掉只留ext4、vfat、squashfs关闭不需要的电源管理框架、内核调试选项设置CONFIG_CC_OPTIMIZE_FOR_SIZEy让内核在尺寸优化模式下编译确认CONFIG_DEBUG_INFOn去掉调试符号内核解压也是一个容易被忽视的点。如果内核使用压缩镜像uImage/zImageCPU在跳转到内核之前要先解压。Cortex-A7解压几MB的内核大约要花50到100毫秒。换成未压缩的内核镜像读取时间变长解压时间消失实测两者差距不超过50毫秒所以我最终保留压缩镜像。内核打印等级也要降。SDK默认的loglevel会打印大量驱动probe信息几百行日志在串口上按115200波特率刷出去耗时几百毫秒。生产环境下把loglevel3甚至loglevel0加上quiet参数启动时内核几乎不出日志时间立刻下来。3.2 initramfs比直接挂rootfs快在哪T113-i SDK默认的rootfs通常放在SD卡或eMMC的某个分区上。内核启动后要等mmc块设备就绪、识别分区、挂载文件系统然后才执行/sbin/init。这一串流程里mmc驱动probe、eMMC/SD卡自身初始化、文件系统superblock读取每一步都是可感知的延迟。把rootfs打成cpio.gz压缩包做成initramfs由U-Boot加载进内存情况就完全不一样了。initramfs在内核初始化过程中直接被挂载为根文件系统不需要等待任何块设备就绪。这个改动让“内核启动到执行/sbin/init”的时间从1.2秒左右降到了0.6秒收益非常显著。initramfs也有代价镜像文件变大占用内存rootfs更新时要重新打包。我的折中方案是initramfs里只放最小集——init程序、UI应用本身、必需的运行库和字体其他图片、资源、配置全部留在eMMC数据分区init脚本里先挂载数据分区再启动应用。这样既保留了initramfs的快速启动优势又不牺牲升级灵活性。3.3 busybox init启动脚本的串行问题T113-i SDK默认用busybox init它按照/etc/inittab的顺序串行执行rcS脚本。如果rcS里有mount -a、mdev -s、然后一排/etc/init.d/Sxx_xxx脚本挨个跑每个脚本的fork、执行、等待都会累加到启动时间里。优化思路是能砍则砍能合并则合并。最终的rootfs启动脚本连10行都不到做的事情只有三件挂载proc、sysfs、tmpfs然后直接exec UI进程。这里特别提一下mdev -s。mdev是busybox的设备管理器-s参数会在启动时扫描sysfs并创建所有设备节点。对于硬件固定的嵌入式设备设备节点完全可以静态创建或者依赖devtmpfs自动管理并不需要每次启动都做一次全量扫描。去掉mdev -s之后启动时间能省下100到200毫秒而且没有任何副作用。应用也尽量不要写在rcS末尾而是让inittab直接拉起应用。busybox init的respawn字段可以指定应用路径比先启动shell脚本再在脚本末尾exec应用少一层fork开销。4. Qt界面启动提速linuxfb选型与运行时清理4.1 编译期的取舍Qt 5.15.2的configure参数项目里用的Qt版本是5.15.2这是嵌入式领域用得最多、坑也相对少的一个版本。Qt的启动速度很大程度上在configure阶段就决定了。T113-i平台上我最终确认的configure思路是走linuxfb平台插件而不是eglfs。有些资料会鼓吹eglfs有GPU加速体验更好但前提是平台具备完整可用的GPU驱动栈。T113-i这类定位成本敏感的芯片GPU驱动往往不完整或者根本没有独立的3D渲染单元eglfs初始化EGL上下文反而会多花一两百毫秒最终渲染也未必更快。linuxfb直接把Qt绘制结果写到/dev/fb0链路短可控性强。configure的关键参数组合./configure \ -no-xcb -no-xkbcommon \ -no-fontconfig -no-icu \ -no-gstreamer -no-opengl \ -linuxfb \ -release -static-no-fontconfig这一步很关键。fontconfig会在启动时扫描系统全部字体文件构建字体数据库耗时常常在300毫秒以上。嵌入式Linux下强制关闭它Qt改用直接指定字体文件的方式字体加载开销降到几乎为零。-static静态链接会让Qt可执行文件体积变大但省掉了运行时加载大量.so动态库的时间。实测静态链接后Qt程序从开始加载到main()执行的时间能省下200毫秒左右。代价是最终可执行文件可能有几十MB对存储空间紧张的产品需要权衡。configure里面还有一个容易踩的模块问题关闭了某些模块后pro文件里如果写了QT serialport之类的内容编译会报unknown module in qt:serialport。解决方法是同步清理工程文件里不需要的模块引用不要遗留。4.2 运行时减负的几个环境变量Qt程序放在板子上跑默认行为会做很多“多余”的事情。第一个要处理的就是插件扫描。Qt启动时会按照平台插件路径、imageformats路径、QML导入路径去扫描目录下的所有插件模块目录下的文件越多扫描时间越长。把插件目录精简到只剩用到的几个扫描时间可以从几百毫秒降到几十毫秒。我最终在启动脚本里固定设置的变量export QT_QPA_PLATFORMlinuxfb:fb/dev/fb0:size1024x600:mmSize1024x600 export QT_QPA_FONTDIR/usr/share/fonts export QT_PLUGIN_PATH/opt/plugins export QT_LOGGING_RULES*falseQT_QPA_PLATFORM指定linuxfb平台并明确framebuffer设备和屏幕尺寸避免Qt去检测QT_PLUGIN_PATH指向一个精简过的插件目录里面只保留platforms和imageformats两个子目录QT_LOGGING_RULES关掉所有Qt日志输出避免启动时代码里的qDebug在串口上刷屏。串口打印这种毫秒级的操作在UI首帧期间出现几百条影响同样不可忽略。业务代码层面的一个建议如果你在代码里用了大量qDebug/qInfo在release构建时通过QT_NO_DEBUG_OUTPUT宏统一禁掉而不是仅仅依赖运行时规则。运行时规则只是不显示但字符串格式化开销还在编译期禁掉才是零成本。4.3 首帧优先的界面构造顺序Qt程序启动慢往往不是Qt框架本身慢而是main()函数里写的东西太多。很多人习惯的做法是创建QApplication直接new主窗口然后在主窗口构造函数里加载图片、读数据库、连接网络全做完之后才调用show()。这样用户看到黑屏的时间被无限拉长。正确的做法是首帧优先QApplication初始化后立刻创建主窗口对象但此时只设置背景色和基础布局不加载任何重量级资源。立即调用show()和QApplication::processEvents()这一帧画面马上输出到屏幕用户感知到的就是“界面出来了”。图片加载、数据初始化、网络连接全部放到单独的工作线程或者放到首帧显示之后的延时任务里按优先级逐个完成。这个优化通常能把Qt的首帧时间从3秒压到1秒以内。要注意的是Qt的linuxfb插件在显示第一帧后会主动做一次全屏重绘如果在show()之前对framebuffer做了清屏操作这时的画面已经干净不会出现残留问题。还有一个小技巧把QML的编译缓存提前做好用qmlcachegen生成缓存文件避免QML文件在运行时被解释编译。如果用的是Qt Widgets而非QML这步可以跳过Widgets在编译期已经完成C编译启动开销更低。5. LVGL方案换一个更轻的渲染内核5.1 LVGL在T113-i上的接入方式有些产品界面本身并不复杂只有按钮、标签、简单图表、轮播图这种情况下LVGL远比Qt合适。LVGL不依赖QObject、事件循环、字体引擎这类重型框架直接从framebuffer绘制资源占用小启动开销几乎可以忽略。在T113-i的Linux系统上移植LVGL核心就是三件事。第一提供一个flush函数把LVGL的绘制缓冲拷贝到/dev/fb0static void fb_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { lcd_fb_copy(area, color_p); lv_disp_flush_ready(drv); }第二提供一个读取输入设备的函数接收触摸事件。使用tslib或者直接读evdev节点都行将坐标和按下状态转换成lv_indev_data_t结构提交给LVGL。第三在定时器或者主循环里周期性调用lv_timer_handler()驱动LVGL的事件处理和重绘。void ui_thread(void) { lv_init(); lv_disp_draw_buf_init(draw_buf, buf1, buf2, screen_width * 40); lv_disp_drv_register(disp_drv); lv_indev_drv_register(indev_drv); ui_create_main_screen(); lv_timer_handler(); }LVGL对运行环境的要求非常低即使不跑RTOS直接在Linux用户空间用普通线程循环调用lv_timer_handler也能稳定运行。有些人会把LVGL放到T113-i那颗RISC-V协处理器上配合FreeRTOS跑把界面刷新和Linux主系统完全隔离这是另一种玩法但本文讨论的是Linux主系统下的快速启动LVGL直接跑在Cortex-A7的用户空间同样能达到目标。5.2 lv_conf.h的裁剪要点LVGL有一个l v_conf.h配置文件编译期功能裁剪都在这里做。不用的组件、主题、动画扩展统统关掉既能减小代码体积也能减少初始化的检查项。我实际用到的裁剪项配置项建议值说明LV_MEM_SIZE4MB1024x600的HMI界面足够LV_MEM_CUSTOM1使用标准malloc管理堆内存LV_FONT_MONTSERRAT_141只保留用到的字号LV_FONT_MONTSERRAT_480关闭大字号完整字体LV_USE_LOG0正式版关闭日志LV_TICK_CUSTOM1使用系统已有的时基不另起线程LV_USE_FLEX / LV_USE_GRID按需不用就关掉字体是最值得花时间裁剪的。LVGL内置字体只有拉丁字符集中文需要自己用lv_font_conv工具生成只包含产品界面里实际出现的汉字和符号。一个纯数字加少量汉字的HMI界面字体文件可以压到几十KB同时避免启动时加载过大的字体数组。LV_TICK_CUSTOM建议设置为1让LVGL复用系统已有的1毫秒时基源而不是内部再用一个线程维护lv_tick。这样减少一次线程切换在快速启动场景下是有实际收益的。5.3 首屏点亮与Qt方案怎么选LVGL虽然轻但首次创建大量控件、渲染首帧仍然需要时间。为了把“用户看到画面”的时间尽可能提前可以在lv_init()之前直接对/dev/fb0做一次memset填充背景色。这样屏幕上电后300毫秒内就有了颜色变化用户的第一感受是“设备已经醒了”之后LVGL控件再慢慢绘上来就不觉得慢。int fb_fd open(/dev/fb0, O_RDWR); unsigned int *fb_base mmap(NULL, screen_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb_fd, 0); memset(fb_base, 0xff, screen_size); // 白底或品牌色关于Qt和LVGL怎么选我的原则是二选一而不是同时用。两者混跑会争抢framebuffer、输入设备和DMA通道调试起来非常痛苦。界面复杂度高、需要图表库或Web内容选Qt只做仪表、菜单、参数显示LVGL能比Qt方案再省0.2到0.3秒。6. 合入实测时间账单与踩坑记录6.1 优化前后时间对比所有优化项合入后在eMMC存储、1024x600屏幕的硬件配置上重新测量数据如下启动阶段默认固件优化后Qt方案优化后LVGL方案Boot ROM SPL0.65s0.42s0.42sU-Boot主程序1.10s0.30s0.30sKernel initramfs2.40s0.78s0.78s应用首帧4.50s0.90s0.60s合计8.65s2.40s2.10sQt方案实测2.43秒LVGL方案2.17秒都通过了2.5秒的验收线。但这个结果并不是一蹴而就的过程中踩了一串坑每一个都值得单独记一笔。6.2 踩坑一启动画面残留导致首帧花屏最早优化完U-Boot把启动LOGO直接传到内核显示结果Qt首帧出现时屏幕上还残留着LOGO的一部分。排查发现Qt的linuxfb后端不会在初始化时自动清屏framebuffer里存的内容还是内核LOGO的画面Qt只是把新窗口绘制在上层没有清除的区域就残留了。解决办法是在UI进程启动后、创建窗口之前先对framebuffer做一次整体填充代码和上面LVGL首屏填充一样几毫秒就能完成。这里提醒一下如果用了U-Boot splash和内核LOGO要做到“画面无缝切换”最稳妥的方式是让U-Boot和内核的画面背景色与应用首帧背景色保持一致不要来回跳变。6.3 踩坑二日志关了就没法排障把loglevel调到3、U-Boot静默之后启动失败的排障难度直线上升屏幕黑一下直接没反应串口又没有输出根本不知道卡在哪一步。后来我留了一手U-Boot环境变量里预设了一个调试开关。bootcmd先读取一个GPIO电平如果拉高就往bootargs里追加consolettyS0,115200 loglevel8否则保持生产模式的零日志状态。这样平时产品完全静默需要调试时接一根线就能把完整启动日志捞出来。内核和应用的日志也做了类似处理平时不输出但/var/log目录保留应用启动到一定阶段后把关键状态写入临时文件排障时检查文件内容就能定位问题。6.4 踩坑三DDR参数调过头高温老化直接翻车SPL阶段的DDR初始化参数直接影响整个系统能不能跑起来。我为了把SPL时间再压几十毫秒尝试跳过DDR扩展训练、把某些时序参数调整到更激进的档位。室温环境下测试一切正常结果放进高温老化箱后问题就出来了系统随机死机、启动失败、重启循环。这个教训让我彻底明白了一个道理快速启动不能以牺牲稳定性为代价。操作系统层面的优化空间已经足够完全没必要去跟DDR训练较劲。最终我把DDR参数恢复到SDK默认值启动时间表上多花了0.05秒但换来了全温度区间下的稳定运行。快速启动优化最重要的原则就是别碰你不完全理解的底层时序参数除非你有专门的硬件测试工程师和充足的老化验证时间。6.5 踩坑四Qt在T113-i上报linuxfb插件找不到Qt程序部署到板子上运行时报qt.qpa.plugin: could not find the qt platform plugin linuxfb这个问题在网络上一搜一大把但很多人没搞明白真正原因。这个报错背后有两种可能。第一种configure编译Qt时没带-linuxfb选项导致编译产物里没有libqlinuxfb.so。第二种编译产物里有这个库但运行时QT_QPA_PLATFORM_PLUGIN_PATH环境变量没有指向插件目录Qt找不到。排查方法是用export QT_DEBUG_PLUGINS1再启动程序它会打印插件搜索路径和加载过程。确认编译带上-linuxfb确认插件目录结构正确这两个问题解决之后报错自然会消失。6.6 踩坑五initramfs体积膨胀拖慢解压把整个Qt运行库塞进initramfs以后rootfs镜像膨胀到60多MB内核解压cpio进DDR的过程明显变慢同时占用了大量内存应用可用内存反而变少。这是一个容易被忽略的隐形坑initramfs不是越大越好它要经过压缩、搬运、解压三个阶段体积越大三个阶段全部变慢整体算下来可能比直接挂载eMMC分区还要慢。最终的瘦身方案是initramfs里只保留UI程序本体、libQtCore和linuxfb插件图片、字体、布局文件全部放eMMC数据分区。init脚本先挂载数据分区然后启动应用。initramfs体积控制在12MB以内解压时间减少了一半内存也省了出来。6.7 踩坑六Qt日志噪音与串口资源竞争没有关Qt日志之前Qt程序启动时会有一堆dbus、ALSA、xkb相关的提示输出。这些输出在功能上完全没用但在115200波特率的串口上累积起来耗时能有几百毫秒并且会在应用首帧期间抢占系统资源。第一反应是设置QT_LOGGING_RULES*false但更彻底的办法还是在configure阶段把不需要的模块直接关掉从源头避免日志产生。另外要检查和业务代码里是否有线程直接往串口设备写日志如果有首帧完成之前一定要关掉否则UI线程和日志线程争抢串口锁画面停顿就成了必然。最后一些建议快速启动优化一定要建立版本基线每改一处把启动时间记录到表格或者issue里。时间表走到最后你会发现很多优化项是叠加而不是简单相加——U-Boot少打印100个字符和内核少打印500行合在一起省下的时间往往超过各自独立测量之和。我在这个项目里就是靠逐项记录最后一轮合入后Qt方案停在2.43秒LVGL方案2.17秒比目标还留了一点余量。整个项目做完我最深的体会是快速启动不是一个玄学领域它本质上就是一份时间账。每一阶段花了多少毫秒哪些开销是必需的哪些是配置不当造成的浪费全部摊开之后优化路径自然就出来了。真正难的从来不是裁剪本身而是确定哪些时间可以省、哪些时间绝不能碰的边界判断能力。T113-i平台的整体启动链路非常透明SPL、U-Boot、内核、用户空间各有各的优化手段把链路拆清楚2.5秒的目标并不遥远。
返回列表