SchedTune學習筆記


本文僅是對kernel中的document進行翻譯,sched-tune內核文檔路徑:kernel/Documentation/scheduler/sched-tune.txt

1. 為何引入schedtune?

schedutil是一個基於利用率驅動的cpu頻率governor。它允許調度器為了cpu上運行的task選出最優的工作頻率點(DVFS operating point: OPP)。

但是,有時候我們需要故意進行boost,來滿足特定場景下的性能要求,盡管這樣會產生更大的功耗。比如,為了縮短task的響應時間,我們希望task運行在一個比實際cpu帶寬要求更高的OPP。

還有一個重要原因是我們想用schedutil governor來替代當前所有的CPU Freq pollicy。schedutil這個governor是基於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提供了一套用戶接口的工具,用於功耗-性能調節。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 (1024)作為最大值,所以margin就為:

margin := sched_cfs_boost * (SCHED_CAPACITY_SCALE - signal)

使用這種boosting strategy:

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

每一個在sched_cfs_boost內的值,都會放大signal的值

假如使用SPC的boosting策略來選擇OPP的話,那么:

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

這說明在50% boosting的時候,task會在理論最大性能一半的情況下運行。

下圖表示了SPC boost之后的信號圖(來自sched-tune.txt):

 a) "-" represents the original signal
 b) "b" represents a  50% boosted signal
 c) "p" represents a 100% boosted signal


   ^
   |  SCHED_LOAD_SCALE
   +-----------------------------------------------------------------+
   |pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
   |
   |                                             boosted_signal
   |                                          bbbbbbbbbbbbbbbbbbbbbbbb
   |
   |                                            original signal
   |                  bbbbbbbbbbbbbbbbbbbbbbbb+----------------------+
   |                                          |
   |bbbbbbbbbbbbbbbbbb                        |
   |                                          |
   |                                          |
   |                                          |
   |                  +-----------------------+
   |                  |
   |                  |
   |                  |
   |------------------+
   |
   |
   +----------------------------------------------------------------------->

從圖中可以看到,50% boost的情況下,boost后的信號都會提升當前signal與最大值之間差值的一半。100% boost的情況下,boost后的signal一直處於最高 。

schedutil的調頻的計算方法:

         1.25 * cpuinfo.max_freq
f = ———————————————————————————————— * boosted_util
            cpu_max_capacity

         1.25 * cpuinfo.max_freq
  = ———————————————————————————————— * [util + (1024 - util) * boost_percent],//boost_percent是schedtune配置的boost值
            cpu_max_capacity


其中util計算公式如下:

            prev_runnable_sum * (100 + sched_load_boost)
util = ———————————————————————————————————————————————————————, //prev_runnable_sum是WALT統計的值,window_size默認20ms
                    window_size >> 10 * 100

 

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()返回CFS任務使用的CPU的容量。 返回值的單位必須是容量之一,因此我們可以將利用率與CFS任務可用
的CPU容量(即cpu_capacity)進行比較。

* cfs_rq.avg.util_avg是可運行任務的運行時間加上CPU上當前不可運行任務的最新利用率的總和。它表示[0..capacity_orig]
范圍內的CPU利用率,其中Capacity_orig是最高頻率下可用的cpu_capacity(arch_scale_freq_capacity() I: 最大的容量是1024,
和利用率相比的時候容量也使用的是百分比)。

* CPU的利用率收斂到等於或小於CPU當前容量(capacity_curr <= Capacity_orig)的總和,因為它是該CPU上的運行時間,
由Capacity_curr縮放。

*但是,由於cfs.avg.util_avg中不幸的圓整舍入,或者恰好在遷移任務和新任務喚醒之后,直到平均值隨着新的運行時間穩定下
來之后,cfs_rq.avg.util_avg可能高於Capacity_curr,甚至高於Capacity_orig。 我們需要檢查利用率是否保持在[0..capacity_orig]
范圍內,並在必要時對其進行限制。 如果沒有使用率上限,則一個組可能會被視為過載(CPU0利用率為121%+ CPU1利用率為80%),
而CPU1具有20%的可用容量。 我們允許利用率超調Capacity_curr(而不是capacity_orig),因為它可用於預測任務遷移(計划程序驅動的DVFS)之后所需的容量。
*/
cpu_util() //kernel/sched/sched.h
boosted_cpu_util() //kernel/sched/fair.c

其中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值(注:上面的bost是per-CPU的,這個是per-group_task的)。 如果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          4        12          1
cpu            3        1          1
cpuacct         1        232          1
schedtune        2         5           1 //this
freezer         0         1          1

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 100 > /sys/fs/cgroup/stune/performance/schedtune.boost

android平台下,無法創建新的group。創建報錯:

/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=0 (default - use energy-aware task placement if available) 即功耗優先
prefer_idle=1 (never use energy-aware task placement for these tasks) 即性能優先

因為在CFS中,為了性能(縮短wakeup延遲), 一般的wakeup task placement邏輯對性能優先有一定傾向性。這個屬性就可以對wakeup延遲有要求的task有效果的同時,也仍然允許energy-aware wakeup placement來迎合其他task,來節省功耗。

 

7. Q&A

1.如何管理具有不同提升值(boost)的多組任務?

當前的SchedTune實現跟蹤在CPU上boost的RUNNABLE任務。 一旦sched-DVFS選擇運行CPU的OPP,將以其runqueue中當前RUNNABLE任務的boost值的最大值來提升CPU利用率。這使sched-DVFS僅在有boost任務准備運行時才boost CPU,並在最后一個boost任務出隊后立即切換回節能模式。

 

參考:

https://www.cnblogs.com/lingjiajun/p/12561177.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM