Skip to content

Latest commit

 

History

History
198 lines (151 loc) · 7.32 KB

hacking.org

File metadata and controls

198 lines (151 loc) · 7.32 KB

基本原理

readahead是可以提高系统冷启效率的,不论是磁盘控制器还是 kernel都使用了此技巧.page cahce甚至swap cache都做了readahead处理, 并且提供了readahead(2), fadvise(2), madvise(2)等syscall让用户态辅助进行.

基于page的readahead可利用的信息有限,基本只能利用数据局部性这一特征. kernel能感知的上层逻辑有限,只能以page为单位,粗暴的连续 读取一定数量的后续page.

readahead可行是因为

  1. 磁盘大部分时间处于空闲状态.
  2. 磁盘IO偏向与读取.
  3. 用户日常使用到的磁盘内容都集中在一部分固定区域.(一般都小于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操作.

    目前实现了以下事件类型

    1. X11 App 事件
    2. systemd unit 事件
    3. process 事件
    4. file system 事件
    5. inner 内部 事件
    6. snapshot 事件

配置文件格式

warm-sched需要用户基于具体情况提供配置文件. 文件格式为json. 大致分为3个部分:

  1. 基本信息: ID, Description, TryFile
  2. Capture信息: Capture方式, 生命周期, 延迟时间, 触发事件列表
  3. 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"
                ]
            }
        ]
    }
}

运行流程

基本流程

  1. systemd在local-fs.target出现后,lightdm.service之前通过warm-sched.service启动warm-daemon
  2. warm-daemon的events模块监听各类事件源,并根据配置文件执行对应的capture或apply操作.
  3. 进入DE环境后,通过/etc/xdg/autostart/机制启动warmctl -u传递inner:user事件,并更新相关环境变量.

退出机制

  1. warm-daemon -timeout 默认最多运行30分钟
  2. warm-daemon -lowMemory 默认在可用内存不足200M时自动退出
  3. 若所有的配置数据已经全部处理完毕则直接退出.

制作配置文件

  1. 开启debug模式, 避免warm-daemon自动退出
    sudo touch /var/lib/warm-sched/cache/debug
        
  2. 丢弃当前disk cache减少干扰
    echo 3 | sudo tee /proc/sys/vm/drop_caches
        
  3. 对比目标进程启动前后的disk cache情况.
    warmctl -t test
        
  4. 参考/var/lib/warm-sched/etc/firefox.json的配置编写一个初始配置. TODO: warmctl提供一个模板生成功能.
  5. 重启后打开对应应用,成功capture后. 重启观察效果. 可直接执行 warmctl 观察是否制作成功. 或使用journalctl查看具体日志.
  6. 若效果不理想, 则进入DE后重复执行步骤2观察遗漏的文件列表.

已知问题

  1. warm-daemon不在swap-sched的cgroup管控下,因此预热的内存在全局LRU上. 如果内存较低(2G)时, 则只能配置基本的预热以及一个chrome的预热,否则会导致使用swap引起磁盘读写. 目前测试的情况: 2G下, 无法同时支持firefox和chrome. 2.5G下可以正常工作.
  2. “systemd”事件目前不支持别名,也就是只能写lightmd.service,不能写display-manager.service
  3. 若使用到了”x11”, “$HOME”等则需要依赖”inner:user”以便相关环境变量准备就绪.

加载时误差累积

若某次做snapshot的时候抓取到了错误的数据,那么很可能造成错误数据之后一直被加载. 这样即使错误数据只有1%, 多次累积后就会造成错误数据比例过大.

错误数据类型

  1. 日志文件.
  2. 非必须文件,比如IDE打开的某个工程项目.或gdb打开的debug文件.
  3. 临时文件,比如每次启动时创建在随机目录下的内容.

解决思路

  1. 名单匹配过滤. 如过滤/tmp, /run, /var/long等目录 此方式可用发展为更高级的UserAPI
  2. 验证性丢弃. 若加载后未被使用,则取消之前的记录. (NOTE:目前无法实现, 除非kernel提供文件是否被访问的机制. 可以考虑Access Time)
  3. 试探性丢弃.按一定规律放弃部分数据的加载.此方式是方案2无法实现的折中方案.

目前可用方式

  1. 配置Capture时,指定Lifetime参数在一定周期后,重新制作snapshot, 并且尽量避免 直接使用mincores这种容易引入累积误差的capture method.

探测时误差

目前虽然使用mincores可以快速获得inode的实际情况(大概120ms), 但针对的是global状态. 整个项目是基于event source来构架的,若event A与event B在时间上发生重叠则 收集到的数据很可能出现重叠.

解决思路

  1. 接管event source的启动过程,利用cgroup之类的技术准确获取访问过的文件.

目前可以方式

  1. 尽量通过”uiapp”, “filelist”等capture method方式, 并配置好合理的黑名单.