本文仅是对kernel中的document进行翻译,便于理解。后续再添加代码分析。

1. 为何引入schedtune?

schedutil是一个基于利用率驱动的cpu频率governor。它允许调度器为了cpu上运行的task选出最优的工作频率点(DVFS operating point: OPP)。

但是,有时候我们需要故意进行boost,来满足特定场景下的性能要求,尽管这样会产生更大的功耗。比如,为了缩短task的响应时间,我们希望task运行在一个比实际cpu带宽要求更高的OPP。

还有一个重要原因是我们想用schedutil governor来替代当前所有的CPUFreq pollicy。schedutil是基于event的,而当前governor是基于采样的,所以schedutil对task选择最优OPP的更加迅速。但是仅仅跟踪实际的task使用率可能不足以表达当前的性能。比如,它不能做到类似“performance”、“interactive” CPUFreq governor的相关行为。

于是,就引入了schedtune。它是一套处于governor架构上层的、可调节的工具,扩展了对task performance boosting的支持。

performance boosting的意思:缩短task启动的时间。例如,一个task从唤醒到其再次休眠或者退出的时间;或有一个周期执行的task,在合适的OPP下,每20s执行5s,当boost之后,执行时间都会缩短至5s以下。

2. 什么是SchedTune

schedtune提供了一套用户接口的工具,用于功耗-性能调节:stune。schedtune是cgroup的一个子系统。所以在cgroup的mount节点下,stune分别为每个group,都提供了2个调节开关:

/<stune cgroup mount point>/schedtune.prefer_idle
/<stune cgroup mount point>/schedtune.boost

在android平台下,目录为:

htc_imedugl:/ # ls /dev/stune
background notify_on_release schedtune.prefer_idle
cgroup.clone_children release_agent schedtune.sched_boost_enabled
cgroup.procs rt schedtune.sched_boost_no_override
cgroup.sane_behavior schedtune.boost tasks
foreground schedtune.colocate top-app

user-space可以通过stune提供的接口随意改变相关相关属性,来适配当前的task运行的环境。比如,background、interactive、low-priority。

2.1 Boosting

boost的值用int型表示,范围为[0, 100]。

boost默认值为0,代表CFS调度器会工作在能耗最低的状态。这也意味着schedutil使task跑在最低的OPP。

boost值100,则表示调度器为工作在性能最高的状态,同时OPP也处在最大。

0-100的范围可以根据其他场景来进行适当调节。比如,优化交互的响应、电池电量变化等。

总体的SchedTune模块是架构在PELT(Per-Entity Load Tracking)和会影响OPP的schedutil两者之上的。

每次task在cpu上申请,就有机会针对工作负载需要而调节该cpu的cpufreq。实际使用的cpufreq会被task所在cgroup的boost值影响。

在frameworks存在的这种影响能够在尽量少修改调度器的前提下,实现仅仅通过一个简单的开关来达到多种不同动作。

在EAS调度器中,我们使用经过boost之后的task util和cpu util来计算energy,以及用于energy-aware的task分配。

2.2 prefer_idle

这是一个控制调度器节省功耗优先,还是性能优先的flag。

默认值0,会让CFS调度器根据energy-aware wakeup策略来分配在group中的task。(功耗优先)

当值设为1,会让CFS调度器分配task时,有最小的wakeup延迟。(性能优先)

android平台下使用这个flag用来表示正在和用户交互的应用。

设为1的节点:

dev/stune/foreground/schedtune.prefer_idle
dev/stune/top-app/schedtune.prefer_idle

设为0节点:

dev/stune/background/schedtune.prefer_idle
dev/stune/rt/schedtune.prefer_idle

3. Signal Boosting策略

整个PELT工作是基于一系列对cpu带宽需求、cpu capacity的负载跟踪signal而构建的。而SchedTune背后就是通过变大其中一些负载跟踪的signal,来使task或者runqueue看上去需要比实际的情况更多的性能。

而具体是哪个信号,取决于特定的“consumer”。但不管怎么样,为“boosting signal”定义一个简单有效的固定方法是很重要的。

boosting策略如下定义了user-space控制的sched_cfs_boost值是如何翻译成内部“margin”参数值,并加到其需要影响的信号上的:

margin         := boosting_strategy(sched_cfs_boost, signal)
boosted_signal := signal + margin

在SchedTune中实现的boosting strategy叫做:'Signal Proportional Compensation' (SPC)。有了SPC,sched_cfs_boost就会被成比例地补偿到原signal值,最后赋给margin。如果计算之后signal到达了最大值,那么sched_cfs_boost就等于当前signal的实际值与最大值的差值。

因为调节用的signal使用SCHED_CAPACITY_SCALE作为最大值,所以margin就为:

margin := sched_cfs_boost * (SCHED_CAPACITY_SCALE - signal)

使用这种boosting strategy:

100% sched_cfs_boost代表着signal放大到最大值。

每一个在sched_cfs_boost内的值,都会放大signal的值

假如使用SPC的boosting策略来选择OPP的话,那么:

-   % boosting: run the task at the minimum OPP required by its workload
- % boosting: run the task at the maximum OPP available for the CPU
- % boosting: run at the half-way OPP between minimum and maximum

这说明在50% boosting的时候,task会在理论最大性能一半的情况下运行。

下图表示了SPC boost之后的信号图:

 a) "-" represents the original signal
b) "b" represents a % boosted signal
c) "p" represents a % boosted signal ^
| SCHED_CAPACITY_SCALE
+-----------------------------------------------------------------+
|pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
|
| boosted_signal
| bbbbbbbbbbbbbbbbbbbbbbbb
|
| original signal
| bbbbbbbbbbbbbbbbbbbbbbbb+----------------------+
| |
|bbbbbbbbbbbbbbbbbb |
| |
| |
| |
| +-----------------------+
| |
| |
| |
|------------------+
|
|
+----------------------------------------------------------------------->

从图中可以看到,

50% boost的情况下,boost后的信号都会提升当前signal与最大值之间差值的一半。

100% boost的情况下,boost后的signal一直处于最高 。

4. 使用boost的CPU util的OPP选择

我们看到boost的实现并没有使用新的负载signal,而是用一个api来调节现有的signal。调节是基于需求,并且仅在调度器的相关代码路径中。这个新的api根据sched_cfs_boost的值,决定了最终要么return原先的signal,要么return boost后的signal。这对现有代码修改非常简洁。

根据之前提到的SPC策略,signal代表了一个boost后的cpu util。对schedutil来说,这让一个cpu(比如CFS run queue)出现比原先更多的使用。

因此在sched_cfs_boost有效的情况下,我们使用下面的函数来获取当前cpu的util:

cpu_util()
boosted_cpu_util()

其中boosted_cpu_util()会return被 sched_cfs_boost作用之后的cpu util。

这个函数被CFS调度器的代码中用于决定cpu OPP。例如,将boost设为100%,cpu就是泡在最高的OPP。

5.Per task group boosting

在使用电池供电的设备上,会有很多后台service一直处于running状态,此时它们就需要节省功耗优先的调度策略。同时,一些交互性的app则对性能更敏感,需要放弃功耗,选择最高的性能。

为了能更好的应对上述情况,schedtune扩展了一个更广泛的boosting接口。它能让不同task group配置和使用不同的boosting值。如果task需要特殊的性能要求,那么就把它分到另一个cgroup中。boost通过以下接口来设置:

schedtune.boost

这个boost值对应了该group中所有task会进行SPC boosting。

目前的schedtune控制有如下主要特性:

1)层级结构中只能创建一层

根节点定义了系统级的boost,默认应用到所有task。下一级子groups命名为“boost groups”,它们为特定的task定义boost值。

再深一层的子groups是不允许创建的,因为对user-space来说没有意义。

2)定义的子group数量有限制

这个数量限制是在编译时确定的,默认是16。需要数量限制的原因有如下2点:

a)在真实系统中,我们不希望有太多特殊的场景。可能我们只要有以下几种就可以了:"background","interactive","performance"。

b)尽可能简化功能。特别是当有不同的boost配置的RUNNABLE tasks时,计算每个cpu boosting

如此简单的设计就能在大多主要场景下,利用简洁的接口来管理所有或者部分task的功耗-性能。并且,这个接口可以简单地集成到user-space中,用于对不同类型的task,进行快速的task boosting。

6.设置和使用

0. kernel config配置中:

CONFIG_SCHED_TUNE=y

1. 检查schedtune cgroup控制器是否available:

htc_imedugl:/ # cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset                  
cpu                     
cpuacct                 
schedtune                
freezer                  

2. 挂载cgroup文件系统(可选)

root@linaro-nano:~# sudo mount -t tmpfs cgroups /sys/fs/cgroup 

3. 挂载schedtune文件系统:

root@linaro-nano:~# mkdir /sys/fs/cgroup/stune
root@linaro-nano:~# sudo mount -t cgroup -o schedtune stune /sys/fs/cgroup/

android平台下,目录路径如下:

htc_imedugl:/ # ls /dev/stune
background notify_on_release schedtune.prefer_idle
cgroup.clone_children release_agent schedtune.sched_boost_enabled
cgroup.procs rt schedtune.sched_boost_no_override
cgroup.sane_behavior schedtune.boost tasks
foreground schedtune.colocate top-app

4. 创建task groups并配置特定的boost(可选)

举例将boost设置100%:

root@linaro-nano:~# mkdir /sys/fs/cgroup/stune/performance
root@linaro-nano:~# echo > /sys/fs/cgroup/stune/performance/schedtune.boost

android平台下,无法创建新的group。创建报错:

|htc_imedugl:/dev/stune # mkdir perf 
mkdir: 'perf': No space left on device

5. 将task移到boost group

root@linaro-nano:~# echo TASKPID > /sys/fs/cgroup/stune/performance/cgroup.procs

android平台下:

echo TASKPID > /dev/stune/GROUPNAME/tasks

6. Per-task & wakeup任务分配策略

许多设备同时会有多个CFS tasks需要最小的wakeup延迟,而也有很多task不关注wakeup延迟。

对于触摸控制的环境,缩短多余的wakeup延迟是非常重要的。

当你使用schedtune时,你可以另一个参数,它可以让一个group标记为是否energy_aware placement bypass:

prefer_idle= (default - use energy-aware task placement if available)
prefer_idle= (never use energy-aware task placement for these tasks)

因为在CFS中,为了性能(缩短wakeup延迟),一般的wakeup task placement逻辑对性能优先有一定倾向性。这个属性就可以对wakeup延迟有要求的task有效果的同时,也仍然允许energy-aware wakeup placement来迎合其他task,来节省功耗。

7. Q&A

在多个groups并各自有不同的boost值的情况下,是如何管理的?

-

目前schedtune保持这跟踪boost后cpu上的RUNNABLE tasks。schedutil可以看cpu util和用来选择合适的OPP。cpu util会经过根据当前RANNABLE tasks中的最大boost值来进行boost。

允许cpufreq去boost cpu 仅当boost后的task准备运行,并且当最后一个boost后taskdequeue时,马上切换回更节省功耗的模式。

最新文章

  1. Java this的一两点使用
  2. single-table inheritance 单表继承
  3. .NET Core Web 应用部署到 Docker 中运行
  4. printf背后的故事
  5. hdu1074 Doing Homework
  6. LeetCode Binary Tree Postorder Traversal(数据结构)
  7. 为什么匿名内部类只能访问其所在方法中的final类型的局部变量?
  8. Apache CXF实现Web Service(5)—— GZIP使用
  9. 2013 Asia Chengdu Regional Contest
  10. Ubuntu 出现apt-get: Package has no installation candidate问题
  11. Main Memory Object-Relational Database Management System
  12. SQL大全基本语法
  13. 微信小程序笔记
  14. openstack Q版部署-----keystone认证服务安装配置(3)
  15. 编译QFileSystemModel
  16. 用DotNetOpenAuth实现基于OAuth 2.0的web api授权 (一)Getting Start
  17. java基础面试题常出现(一)
  18. 《Linux 文本处理》- awk 分析 nginx 日志
  19. nfs共享文件搭建
  20. CentOS 7下搭建配置 SVN 服务器

热门文章

  1. X Error:BadDrawable (individ Pixmap or Window parameter 9)
  2. SQLserver分库分表
  3. python学习第八天--异常和异常处理
  4. Mysql常用sql语句(20)- 子查询重点知识
  5. SDWebImage 原理及使用问题
  6. Xshell 与 Xftp 的安装与使用
  7. java 获取请求ip,服务本地ip
  8. 说一说JS的IIFE
  9. python之模块、类、对象
  10. poj2455 k条路最小化最长边