Linux 启动与优化
- Uboot 优化
- Kernel 优化
- User space 优化
- 开机启动应用程序
摘要:
- 以下优化过程使用到的工具和参考资料下载
Uboot 优化
1. 显示整个系统的运行时间:
sudo grabserial -d /dev/ttyUSB0 -t
2. 通过在Uboot命令行中:
setenv bootdelay 0
saveenv
3. 注释掉 include/configs/colibri_imx6.h 部分功能:
移除一些功能有助于减少分配时间和初始化这些功能的时间。例如移除USB Client和DFU功能 uboot size 从 364k => 348k , 启动时间缩短
4. 减少串口的数据输出
5. 配置和编译uboot:
make colibri_imx6_defconfig
make
Kernel 优化
1. 显示内核启动的运行时间:
sudo grabserial -d /dev/ttyUSB0 -t -m "^Starting kernel*" -q "^\[ *[]0-9.]* Freeing unused kernel memory.*"
2. 指定日志的级别 printk(),减少信息的输出等待时间(内核参数 quiet(静默模式)):
setenv defargs 'enable_wait_mode=off galcore.contiguousSize=50331648 initcall_debug printk.time=1 quiet'
saveenv
然而,这也将屏蔽我们测试启动时间的字符信息(“Freeing unused kernel memory”)。最简单的方法输出这些信息是利用日志级别输出特定的信息。在’mm/page_alloc.c’中搜索“Freeing %s memory”。我将使用‘pr_info => pr_alert’( 将系统的级别 6 变成级别 1 ,控制台只输出比系统级别小的数 )( 为printk定义的宏,打印日志等级,没有指定的日志级别默认为 4 )输出信息 。
3. make menuconfig 移除功能,减小内核尺寸:
裁剪前:
裁剪后:
'dmesg’命令设备故障的诊断非常重要。 在‘dmesg’命令的帮助下进行硬件的连接或断开连接操作时,我们可以看到硬件的检测或者断开连接的信息。'dmesg’常常配合管道符 | 使用。 如: dmesg | more 、dmesg | less 、 dmesg | grep sda 、 dmesg | grep -i usb dmesg | grep -i dma ……
内核启动时各个功能所消耗的时间,可通过Linux源码中 scripts/bootgraph.pl脚本,将启动日志进行图形化分析。
dmesg > boot.log # 在开发板的Linux中
scp boot.log zhousijie@192.168.2.1:/home/zhousijie # 拷贝到上位机cat boot.log | perl scripts/bootgraph.pl > kernel.svg #上位机中
firefox/google-chrome kernel.svg #显示图形化的启动时间占比
4. 配置和编译kernel:
make colibri_imx6_defconfig
make -j3 zImage LOADADDR=10008000
User space 优化
># 屏蔽掉所有的内核printk打印,那么我只需要把第一个数值调到最小值1或者0。
echo 1 4 1 7 > /proc/sys/kernel/printk
echo 0 4 0 7 > /proc/sys/kernel/printk
systemd 和 system V 的主要区别:
- systemd :在多核系统中,并行启动,但依赖关系复杂,优化困难
- system v:串行启动,按顺序启动,便于优化。
??根据实际应用,一个嵌入式系统可能是相对静态的,因此,并不需要Systemd的动态功能。此外,Systemd并不是一个很模块化的系统,各个模块之间由相互依赖关系,这使得精简Systemd变得困难。
=> 嵌入式系统用system v优化。 (判断初始化系统 : stat /proc/1/exe)
1. 使用Systemd(主流)系统初始化 init :
systemd 的最大特点有两个: (systemctl命令格式)
- 令人惊奇的激进的并发启动能力,极大地提高了系统启动速度;
- 用 CGroup 统计跟踪子进程,干净可靠。
1. 我们使用“Freeing unused kernel memory”作为测量基准时间,测量第一个 init 进程到用户登录所用的时间sudo grabserial -d /dev/ttyUSB0 -t -m "^\[ *[]0-9.]* Freeing unused kernel memory.*"init总是Linux的1号进程,是一切进程的父进程。除了系统初始化,init还负责重启、关机、单用户恢复模式。inittab把条目分到不同运行级别。2. systemctl工具可以查看所有的启动项目systemctl statusSystemd提供了systemd-analyze工具,当使用“blame”时,能够打印出各个服务以及其启动的时间。这个可以发现最消耗启动时间的服务。但是,其中的值可能具有迷惑性,因为测量的时间是实际流逝的时间。服务有可能处于睡眠状态,这时的CPU其实在处理其他任务。所以在列表顶部的服务不一定是最耗时的,特别是在单核系统上。默认的BSP中并没有包含 systemd-analyze,可以通过下面的命令,在线安装。opkg updateopkg install systemd-analyze3. systemd-analyze plot也可以用图形的形式输出启动项的情况systemd-analyze plot > systemd.svgfirefox systemd.svg
启动服务可以使用disable命令来关闭。有些服务(特别是Systemd自身提供的)可能需要掩码才能关闭它们。另外有一些可能是系统运行所需的。因此,在关闭服务时需要特别小心,而且一次只能处理一个。
Toradex的BSP中,采用ConnMan作为网络管理工具,可以很灵活的管理无线网络连接。 但ConnMan的启动会消耗较多的时间。
对于不使用网络或仅用有线网络的情况,/etc/systemd/network/wired.network配置可以有效降低启动时间。
systemctl disable connman.service/etc/systemd/network/wired.network
--------------------------------------
[Match]
Name=eth0[Network]
DHCP=ipv4
--------------------------------------在不需要记录系统日志的应用中,将日志存储功能禁用后,也可以在一定程度上缩减启动时间。
/etc/systemd/journald.conf
--------------------------------------
[Journal]
Storage=none
#Compress=yes
--------------------------------------内核参数中的quiet,同样也适用于Systemd。这个有助于Systemd的启动时间。
2. system V 系统初始化 init ,利用搭建好的 Openembedded 架构:
在很长一段时间内,Linux 也使用 SysV 作为标准的 init 系统。由于基于脚本的系统,这是模块化的,并且可以相对容易地精简系统。
特别是对相对静态的系统,并不需要 Systemd 的设备激活和 socket 激活。此时,SysV可以是很好的选择。
Toradex 的 Linux BSP 基于 OpenEmbedded 框架发布,用户可以很方便的配置 SysV。重新编译使用 SysV 的镜像
--------------------------------------
toradex@tdx-lab-linux:~/Toradex/oe-core/v2.5/oe-core/build$ bitbake console-trdx-image
--------------------------------------在使用上面的镜像更新目标板后,在 Linux 执行
--------------------------------------
root@colibri-imx6:~# /usr/sbin/resize.sh
--------------------------------------如果使用的是 Colibri I.MX6D 512MB , 在 U-boot 中执行
--------------------------------------
Colibri iMX6 # patch_ddr_size
--------------------------------------在使用 SysV 的系统上,同样也可以将一些不需要的启动项删除。
--------------------------------------
root@colibri-imx6:~#update-rc.d -f bootlogd remove
root@colibri-imx6:~#update-rc.d -f mountall.sh remove
root@colibri-imx6:~#update-rc.d -f networking remove
--------------------------------------按照上述的优化,User space 启动到Login 的时间为 ~1.1 秒。
--------------------------------------
[1.594064 0.371247] [ 0.661430] Freeing unused kernel memory: 280K (805f6000 - 8063c000)
[0.057864 0.057864] INIT: version 2.88 booting
……[1.098062 0.000060] colibri-imx6 login:
--------------------------------------在 /etc/init.d 建立启动脚本加载应用
--------------------------------------
root@colibri-imx6:vi /etc/init.d/drawing.sh
### BEGIN INIT INFO
# Provides: toradex
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Description: draw rectangles on fb0
### END INIT INFO
/home/root/rectangles &
root@colibri-imx6:chmod a+x drawing.sh
root@colibri-imx6:update-rc.d drawing.sh defaults
--------------------------------------到此,使用上述方法,应用程序能在 2.55 秒时间内启动。
--------------------------------------
ban@LinuxDev:~/software/grabserial-1.8.1$ sudo ./grabserial -d /dev/ttyUSB0 -t
[0.000002 0.000002]
[0.162820 0.162818]
[0.162917 0.000097] U-Boot 2015.04 (Apr 14 2016 - 10:09:25)
……
[0.690563 0.001000] Starting kernel ...
……
[2.633291 0.000076] colibri-imx6 login:
开机启动应用程序
-
通过systemd启动
-
更快显示图形界面步骤:
a.将serialtcp放入/sbin目录下
b. uboot中输入:setenv defargs $defargs init=/sbin/serialtcp
????????saveenv
[进入内核后,尽管很快显示图形界面,但部分接口没完成初始化,导致上述应用可能加载失败,而该方案对环境变量的设置非常有用]