readahead是可以提高系统冷启效率的,不论是磁盘控制器还是 kernel都使用了此技巧.page cahce甚至swap cache都做了readahead处理, 并且提供了readahead(2), fadvise(2), madvise(2)等syscall让用户态辅助进行.
基于page的readahead可利用的信息有限,基本只能利用数据局部性这一特征. kernel能感知的上层逻辑有限,只能以page为单位,粗暴的连续 读取一定数量的后续page.
readahead可行是因为
- 磁盘大部分时间处于空闲状态.
- 磁盘IO偏向与读取.
- 用户日常使用到的磁盘内容都集中在一部分固定区域.(一般都小于RAM大小)
一般来说高速设备访问低速backing store设备时,都会异步读取一定额外数量的内容放入cache中. 若这些额外内容接下来被实际使用则效率能提升多个数量级.
- disk cache
磁盘文件对应的RAM cache数据. 一般等同于kernel中page cache的概念. 可通过以下命令查看当前的page cahce情况
warmctl -c | sort -h
输出内容为当前已经在RAM cache中的磁盘文件数据.
- snapshot
记录某个时间点特定范围内的disk cache情况. warm-sched就是围绕着如何capture snapshot以及如何apply snapshot进行的.
- capture action
将disk cache中对应的文件路径存储下来,以便下次系统启动后apply,加快cache预热 默认capture到的snapshot存储在/var/lib/warm-sched/cache/snap/下
可通过以下命令查看对应snapshot内容
warmctl -dump /var/lib/warm-sched/cache/snap/BASIC
- apply action
将snapshot中记录的文件列表一次性加载到disk cache中.
可通过以下命令加载对应snapshot内容到disk cache
warmctl -a /var/lib/warm-sched/cache/snap/BASIC
apply的实际耗时可以通过以下命令查看
journalctl -u warm-sched -b0
- event sources
执行apply/capture操作时比较困难的是如何找到合适的时机. warm-sched通过配置文件的 形式, 让用户基于不同的event发生情况来进行配置capture和apply操作.
目前实现了以下事件类型
- X11 App 事件
- systemd unit 事件
- process 事件
- file system 事件
- inner 内部 事件
- snapshot 事件
warm-sched需要用户基于具体情况提供配置文件. 文件格式为json. 大致分为3个部分:
- 基本信息: ID, Description, TryFile
- Capture信息: Capture方式, 生命周期, 延迟时间, 触发事件列表
- Apply信息: 触发事件列表, 使用次数补充(并行加载时提高权重)
第三方应用安装对应配置文件到/var/lib/warm-sched/etc/下即可自动获得预热功能.
example
{
"Id" : "google-chrome",
"TryFile": "/opt/google/chrome/chrome", //若此文件不存在则此配置文件会被忽略
"Description": "snapshot configure of google-chrome",
"Apply": {
"After" : [ "snapshot:DE" ], // 等待DE这个snapshot成功apply后再进行本次apply操作
"InitUsage": 10, //apply次数自动加10
},
"Capture": {
// 等待进入user会话 并且 等待WMClass为Google-chrome的X11窗口出现
"After": [ "inner:user", "x11:Google-chrome" ],
// 所有等待事件满足后,延迟1秒再执行capture操作
"WaitSecond": 1,
// 每成功10次apply操作,则重新执行一次capture记录. (满足capture条件时)
"Lifetime": 10,
// capture的具体方式列表.
"Method": [
{
"Type": "uiapp",
"WMClass": "Google-chrome"
},
{
"Type": "filelist",
"FileList": ["$HOME/.config/google-chrome"],
"Blacklist": [
"$HOME/.config/google-chrome/Crash Reports",
"$HOME/.config/google-chrome/Webstore Downloads"
]
}
]
}
}
基本流程
- systemd在local-fs.target出现后,lightdm.service之前通过warm-sched.service启动warm-daemon
- warm-daemon的events模块监听各类事件源,并根据配置文件执行对应的capture或apply操作.
- 进入DE环境后,通过/etc/xdg/autostart/机制启动warmctl -u传递inner:user事件,并更新相关环境变量.
退出机制
- warm-daemon -timeout 默认最多运行30分钟
- warm-daemon -lowMemory 默认在可用内存不足200M时自动退出
- 若所有的配置数据已经全部处理完毕则直接退出.
- 开启debug模式, 避免warm-daemon自动退出
sudo touch /var/lib/warm-sched/cache/debug
- 丢弃当前disk cache减少干扰
echo 3 | sudo tee /proc/sys/vm/drop_caches
- 对比目标进程启动前后的disk cache情况.
warmctl -t test
- 参考/var/lib/warm-sched/etc/firefox.json的配置编写一个初始配置. TODO: warmctl提供一个模板生成功能.
- 重启后打开对应应用,成功capture后. 重启观察效果. 可直接执行 warmctl 观察是否制作成功. 或使用journalctl查看具体日志.
- 若效果不理想, 则进入DE后重复执行步骤2观察遗漏的文件列表.
- warm-daemon不在swap-sched的cgroup管控下,因此预热的内存在全局LRU上. 如果内存较低(2G)时, 则只能配置基本的预热以及一个chrome的预热,否则会导致使用swap引起磁盘读写. 目前测试的情况: 2G下, 无法同时支持firefox和chrome. 2.5G下可以正常工作.
- “systemd”事件目前不支持别名,也就是只能写lightmd.service,不能写display-manager.service
- 若使用到了”x11”, “$HOME”等则需要依赖”inner:user”以便相关环境变量准备就绪.
若某次做snapshot的时候抓取到了错误的数据,那么很可能造成错误数据之后一直被加载. 这样即使错误数据只有1%, 多次累积后就会造成错误数据比例过大.
错误数据类型
- 日志文件.
- 非必须文件,比如IDE打开的某个工程项目.或gdb打开的debug文件.
- 临时文件,比如每次启动时创建在随机目录下的内容.
解决思路
- 名单匹配过滤. 如过滤/tmp, /run, /var/long等目录 此方式可用发展为更高级的UserAPI
- 验证性丢弃. 若加载后未被使用,则取消之前的记录. (NOTE:目前无法实现, 除非kernel提供文件是否被访问的机制. 可以考虑Access Time)
- 试探性丢弃.按一定规律放弃部分数据的加载.此方式是方案2无法实现的折中方案.
目前可用方式
- 配置Capture时,指定Lifetime参数在一定周期后,重新制作snapshot, 并且尽量避免 直接使用mincores这种容易引入累积误差的capture method.
目前虽然使用mincores可以快速获得inode的实际情况(大概120ms), 但针对的是global状态. 整个项目是基于event source来构架的,若event A与event B在时间上发生重叠则 收集到的数据很可能出现重叠.
解决思路
- 接管event source的启动过程,利用cgroup之类的技术准确获取访问过的文件.
目前可以方式
- 尽量通过”uiapp”, “filelist”等capture method方式, 并配置好合理的黑名单.