.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/scheduler/sched-bwc.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: ============ CFS 带宽控制 ============ .. note:: 本文åªè®¨è®ºäº†SCHED_NORMALçš„CPU带宽控制。 SCHED_RT的情况在Documentation/scheduler/sched-rt-group.rst䏿œ‰æ¶‰åŠã€‚ CFS带宽控制是一个CONFIG_FAIR_GROUP_SCHED扩展,它å…许指定一个组或层次的最大CPU带宽。 一个组å…许的带宽是用é…é¢å’Œå‘¨æœŸæŒ‡å®šçš„。在æ¯ä¸ªç»™å®šçš„â€å‘¨æœŸâ€œï¼ˆå¾®ç§’)内,一个任务组被分é…多 达“é…é¢â€å¾®ç§’çš„CPU时间。当cgroupä¸çš„线程å¯è¿è¡Œæ—¶ï¼Œè¯¥é…é¢ä»¥æ—¶é—´ç‰‡æ®µçš„æ–¹å¼è¢«åˆ†é…到æ¯ä¸ªcpu è¿è¡Œé˜Ÿåˆ—ä¸ã€‚一旦所有的é…é¢è¢«åˆ†é…,任何é¢å¤–çš„é…é¢è¯·æ±‚å°†å¯¼è‡´è¿™äº›çº¿ç¨‹è¢«é™æµã€‚è¢«é™æµçš„çº¿ç¨‹å°†ä¸ èƒ½å†æ¬¡è¿è¡Œï¼Œç›´åˆ°ä¸‹ä¸€ä¸ªæ—¶æœŸçš„é…é¢å¾—到补充。 一个组的未分é…é…颿˜¯å…¨å±€è·Ÿè¸ªçš„,在æ¯ä¸ªå‘¨æœŸè¾¹ç•Œè¢«åˆ·æ–°ä¸ºcfs_quotaå•元。当线程消耗这个带宽时, 它以需求为基础被转移到cpu-local“ç’仓â€ï¼Œåœ¨æ¯æ¬¡æ›´æ–°ä¸è½¬ç§»çš„æ•°é‡æ˜¯å¯è°ƒæ•´çš„,被æè¿°ä¸ºâ€œç‰‡â€œï¼ˆæ—¶ 间片)。 çªå‘特性 -------- 现在这个功能借æ¥çš„æ—¶é—´æ˜¯ç”¨äºŽé˜²èŒƒæˆ‘们对未æ¥çš„ä½Žä¼°ï¼Œä»£ä»·æ˜¯å¯¹å…¶ä»–ç³»ç»Ÿç”¨æˆ·çš„å¹²æ‰°å¢žåŠ ã€‚æ‰€æœ‰è¿™äº›éƒ½ 有很好的é™åˆ¶ã€‚ ä¼ ç»Ÿçš„ï¼ˆUP-EDFï¼‰å¸¦å®½æŽ§åˆ¶æ˜¯è¿™æ ·çš„: (U = \Sum u_i) <= 1 这既ä¿è¯äº†æ¯ä¸ªæœ€åŽæœŸé™çš„实现,也ä¿è¯äº†ç³»ç»Ÿçš„稳定。毕竟,如果U>1,那么æ¯ä¸€ç§’é’Ÿçš„å£é’Ÿæ—¶é—´ï¼Œæˆ‘ 们就必须è¿è¡Œè¶…è¿‡ä¸€ç§’é’Ÿçš„ç¨‹åºæ—¶é—´ï¼Œæ˜¾ç„¶ä¼šé”™è¿‡æˆ‘ä»¬çš„æœ€åŽæœŸé™ï¼Œä½†ä¸‹ä¸€ä¸ªæœ€åŽæœŸé™ä¼šæ›´è¿œï¼Œæ°¸è¿œæ²¡æœ‰ æ—¶é—´èµ¶ä¸Šï¼Œæ— è¾¹æ— ç•Œçš„å¤±è´¥ã€‚ çªå‘ç‰¹æ€§è§‚å¯Ÿåˆ°å·¥ä½œè´Ÿè½½å¹¶ä¸æ€»æ˜¯æ‰§è¡Œå…¨éƒ¨é…é¢ï¼›è¿™ä½¿å¾—人们å¯ä»¥å°†u_iæè¿°ä¸ºä¸€ä¸ªç»Ÿè®¡åˆ†å¸ƒã€‚ 例如,让u_i = {x,e}_i,其ä¸x是p(95)å’Œx+e p(100)ï¼ˆä¼ ç»Ÿçš„WCET)。这实际上å…许uæ›´å°ï¼Œæ 高了效率(我们å¯ä»¥åœ¨ç³»ç»Ÿä¸æ‰“åŒ…æ›´å¤šçš„ä»»åŠ¡ï¼‰ï¼Œä½†ä»£ä»·æ˜¯å½“æ‰€æœ‰çš„æ¦‚çŽ‡éƒ½ä¸€è‡´æ—¶ï¼Œä¼šé”™è¿‡æœ€åŽæœŸé™ã€‚ç„¶ è€Œï¼Œå®ƒç¡®å®žä¿æŒäº†ç¨³å®šæ€§ï¼Œå› 为åªè¦æˆ‘们的xé«˜äºŽå¹³å‡æ°´å¹³ï¼Œæ¯ä¸€æ¬¡è¶…é™éƒ½å¿…须与低估相匹é…。 也就是说,å‡è®¾æˆ‘们有两个任务,都指定了一个p(95)值,那么我们有一个p(95)*p(95)=90.25%的机 会,两个任务都在他们的é…é¢å†…ï¼Œä¸€åˆ‡éƒ½å¾ˆå¥½ã€‚åŒæ—¶ï¼Œæˆ‘们有一个p(5)p(5)=0.25%çš„æœºä¼šï¼Œä¸¤ä¸ªä»»åŠ¡åŒ æ—¶è¶…è¿‡ä»–ä»¬çš„é…é¢ï¼ˆä¿è¯æœ€åŽæœŸé™å¤±è´¥ï¼‰ã€‚在这两者之间有一个阈值,其ä¸ä¸€ä¸ªè¶…过了,而å¦ä¸€ä¸ªæ²¡æœ‰ä¸è¶³ï¼Œ æ— æ³•è¡¥å¿ï¼›è¿™å–决于具体的CDFs。 åŒæ—¶ï¼Œæˆ‘们å¯ä»¥è¯´ï¼Œæœ€åçš„æƒ…å†µä¸‹çš„æˆªæ¢æ—¥æœŸå¤±è´¥ï¼Œå°†æ˜¯Sum e_iï¼›ä¹Ÿå°±æ˜¯è¯´ï¼Œæœ‰ä¸€ä¸ªæœ‰ç•Œçš„è¿Ÿå»¶ï¼ˆåœ¨å‡ è®¾x+e确实是WCET的情况下)。 使用çªå‘æ—¶çš„å¹²æ‰°æ˜¯ç”±é”™è¿‡æœ€åŽæœŸé™çš„å¯èƒ½æ€§å’Œå¹³å‡WCETæ¥è¯„价的。测试结果表明,当有许多cgroup或 CPU未被充分利用时,干扰是有é™çš„。更多的细节显示在: https://lore.kernel.org/lkml/5371BD36-55AE-4F71-B9D7-B86DC32E3D2B@linux.alibaba.com/ ç®¡ç† ---- é…é¢ã€å‘¨æœŸå’Œçªå‘是在cpuå系统内通过cgroupfs管ç†çš„。 .. note:: 本节æè¿°çš„cgroupfs文件åªé€‚用于cgroup v1.对于cgroup v2,请å‚阅Control Group v2。 :ref:`Documentation/admin-guide/cgroup-v2.rst <cgroup-v2-cpu>`. - cpu.cfs_quota_us:在一个时期内补充的è¿è¡Œæ—¶é—´ï¼ˆå¾®ç§’)。 - cpu.cfs_period_us:一个周期的长度(微秒)。 - cpu.stat: 输出节æµç»Ÿè®¡æ•°æ®[下é¢è¿›ä¸€æ¥è§£é‡Š] - cpu.cfs_burst_us:最大累积è¿è¡Œæ—¶é—´ï¼ˆå¾®ç§’)。 默认值是:: cpu.cfs_period_us=100ms cpu.cfs_quota_us=-1 cpu.cfs_burst_us=0 cpu.cfs_quota_us的值为-1表示该组没有任何带宽é™åˆ¶ï¼Œè¿™æ ·çš„组被æè¿°ä¸ºæ— é™åˆ¶çš„带宽组。这代表 了CFSçš„ä¼ ç»Ÿå·¥ä½œä¿æŠ¤è¡Œä¸ºã€‚ 写入ä¸å°äºŽcpu.cfs_burst_us的任何(有效的)æ£å€¼å°†é…呿Œ‡å®šçš„带宽é™åˆ¶ã€‚该é…颿ˆ–周期å…许的最 å°é…颿˜¯1ms。周期长度也有一个1s的上é™ã€‚当带宽é™åˆ¶ä»¥åˆ†å±‚æ–¹å¼ä½¿ç”¨æ—¶ï¼Œå˜åœ¨é¢å¤–çš„é™åˆ¶ï¼Œè¿™äº›åœ¨ä¸‹ 颿œ‰æ›´è¯¦ç»†çš„解释。 å‘cpu.cfs_quota_us写入任何负值都会移除带宽é™åˆ¶ï¼Œå¹¶ä½¿ç»„冿¬¡å›žåˆ°æ— é™åˆ¶çš„状æ€ã€‚ cpu.cfs_burst_us的值为0表示该组ä¸èƒ½ç§¯ç´¯ä»»ä½•未使用的带宽。它使得CFSçš„ä¼ ç»Ÿå¸¦å®½æŽ§åˆ¶è¡Œä¸ºæ²¡æœ‰ 改å˜ã€‚å°†ä¸å¤§äºŽ cpu.cfs_quota_us 的任何(有效的)æ£å€¼å†™å…¥ cpu.cfs_burst_us å°†é…呿œªä½¿ç”¨ 带宽累积的上é™ã€‚ 如果一个组处于å—é™çжæ€ï¼Œå¯¹è¯¥ç»„å¸¦å®½è§„æ ¼çš„ä»»ä½•æ›´æ–°éƒ½å°†å¯¼è‡´å…¶æˆä¸ºæ— 陿µçжæ€ã€‚ 系统范围设置 ------------ 为了æé«˜æ•ˆçŽ‡ï¼Œè¿è¡Œæ—¶é—´åœ¨å…¨å±€æ± å’ŒCPU本地“ç’仓â€ä¹‹é—´ä»¥æ‰¹å¤„ç†æ–¹å¼è½¬ç§»ã€‚这大大å‡å°‘了大型系统的全 å±€æ ¸ç®—åŽ‹åŠ›ã€‚æ¯æ¬¡éœ€è¦è¿›è¡Œè¿™ç§æ›´æ–°æ—¶ï¼Œä¼ 输的数é‡è¢«æè¿°ä¸º "片"。 这是å¯ä»¥é€šè¿‡procfs调整的:: /proc/sys/kernel/sched_cfs_bandwidth_slice_us (default=5ms) 较大的时间片段值将å‡å°‘ä¼ è¾“å¼€é”€ï¼Œè€Œè¾ƒå°çš„值则å…许更精细的消费。 统计 ---- 一个组的带宽统计数æ®é€šè¿‡cpu.statçš„5ä¸ªå—æ®µå¯¼å‡ºã€‚ cpu.stat: - nr_periods:已ç»è¿‡åŽ»çš„æ‰§è¡Œé—´éš”çš„æ•°é‡ã€‚ - nr_throttled: 该组已被节æµ/é™åˆ¶çš„æ¬¡æ•°ã€‚ - throttled_time: è¯¥ç»„çš„å®žä½“è¢«é™æµçš„æ€»æ—¶é—´é•¿åº¦ï¼ˆçº³ç§’)。 - nr_bursts:çªå‘å‘生的周期数。 - burst_time: 任何CPU在å„个时期使用超过é…é¢çš„累计å£é’Ÿæ—¶é—´ï¼ˆçº³ç§’)。 è¿™ä¸ªæŽ¥å£æ˜¯åªè¯»çš„。 分层考虑 -------- 该接å£å¼ºåˆ¶è¦æ±‚å•个实体的带宽总是å¯ä»¥è¾¾åˆ°çš„,å³ï¼šmax(c_i) <= C。然而,在总体情况下,是明确 å…许过度订阅的,以便在一个层次结构ä¸å®žçŽ°å·¥ä½œä¿æŠ¤è¯ä¹‰: 例如,Sum (c_i)å¯èƒ½è¶…过C [ å…¶ä¸C是父方的带宽,c_iæ˜¯å…¶åæ–¹çš„带宽。 ] .. note:: 译文ä¸çš„父亲/å©å指的是cgroup parent, cgroup children。 æœ‰ä¸¤ç§æ–¹å¼å¯ä»¥ä½¿ä¸€ä¸ªç»„å˜å¾—陿µ: a. 它在一段时期内完全消耗自己的é…é¢ b. 父方的é…é¢åœ¨å…¶æœŸé—´å†…全部用完 在上述b)情况下,å³ä½¿å©åå¯èƒ½æœ‰å‰©ä½™çš„è¿è¡Œæ—¶é—´ï¼Œå®ƒä¹Ÿä¸ä¼šè¢«å…许,直到父亲的è¿è¡Œæ—¶é—´è¢«åˆ·æ–°ã€‚ CFS带宽é…é¢çš„æ³¨æ„事项 --------------------- 一旦一个片æ–被分é…给一个cpu,它就ä¸ä¼šè¿‡æœŸã€‚然而,如果该cpuä¸Šçš„æ‰€æœ‰çº¿ç¨‹éƒ½æ— æ³•è¿è¡Œï¼Œé‚£ä¹ˆé™¤äº† 1ms以外的所有时间片都å¯ä»¥è¿”å›žåˆ°å…¨å±€æ± ä¸ã€‚这是在编译时由min_cfs_rq_runtimeå˜é‡é…置的。这 是一个性能调整,有助于防æ¢å¯¹å…¨å±€é”çš„é¢å¤–争夺。 cpu-local分片ä¸ä¼šè¿‡æœŸçš„äº‹å®žå¯¼è‡´äº†ä¸€äº›æœ‰è¶£çš„ç½•è§æ¡ˆä¾‹ï¼Œåº”该被ç†è§£ã€‚ 对于cgroup cpué™åˆ¶çš„åº”ç”¨ç¨‹åºæ¥è¯´ï¼Œè¿™æ˜¯ä¸€ä¸ªç›¸å¯¹æœ‰æ„ä¹‰çš„é—®é¢˜ï¼Œå› ä¸ºä»–ä»¬è‡ªç„¶ä¼šæ¶ˆè€—ä»–ä»¬çš„å…¨éƒ¨é… é¢ï¼Œä»¥åŠæ¯ä¸ªcpu-本地片在æ¯ä¸ªæ—¶æœŸçš„å…¨éƒ¨ã€‚å› æ¤ï¼Œé¢„计nr_periods大致ç‰äºŽnr_throttled,并且 cpuacct.用é‡çš„å¢žåŠ å¤§è‡´ç‰äºŽcfs_quota_us在æ¯ä¸ªå‘¨æœŸçš„å¢žåŠ ã€‚ 对于高线程ã€éžcpu绑定的应用程åºï¼Œè¿™ç§éžè¿‡æœŸçš„细微差别å…许应用程åºçŸæš‚地çªç ´ä»–们的é…é¢é™åˆ¶ï¼Œ å³ä»»åŠ¡ç»„æ£åœ¨è¿è¡Œçš„æ¯ä¸ªcpu上未使用的片æ–é‡ï¼ˆé€šå¸¸æ¯ä¸ªcpu最多1ms或由min_cfs_rq_runtime定 义)。这ç§è½»å¾®çš„çªå‘åªé€‚用于é…é¢å·²ç»åˆ†é…ç»™cpuï¼Œç„¶åŽæ²¡æœ‰å®Œå…¨ä½¿ç”¨æˆ–在以å‰çš„æ—¶æœŸè¿”回。这个çªå‘ é‡ä¸ä¼šåœ¨æ ¸å¿ƒä¹‹é—´è½¬ç§»ã€‚å› æ¤ï¼Œè¿™ç§æœºåˆ¶ä»ç„¶ä¸¥æ ¼é™åˆ¶ä»»åŠ¡ç»„çš„é…é¢å¹³å‡ä½¿ç”¨é‡ï¼Œå°½ç®¡æ˜¯åœ¨æ¯”å•一时期更 长的时间窗å£ã€‚这也é™åˆ¶äº†çªå‘能力,æ¯ä¸ªcpuä¸è¶…过1msã€‚è¿™ä¸ºåœ¨é«˜æ ¸æ•°æœºå™¨ä¸Šæœ‰å°é…é¢é™åˆ¶çš„高线程 应用æä¾›äº†æ›´å¥½çš„æ›´å¯é¢„测的用户体验。它还消除了在使用低于é…é¢çš„cpu时对这些应用进行节æµçš„倾å‘。 å¦ä¸€ç§è¯´æ³•是,通过å…许一个片æ–的未使用部分在ä¸åŒæ—¶æœŸä¿æŒæœ‰æ•ˆï¼Œæˆ‘们å‡å°‘了在ä¸éœ€è¦æ•´ä¸ªç‰‡æ–çš„cpu æ—¶é—´çš„cpu-local ç’仓上浪费é…é¢çš„å¯èƒ½æ€§ã€‚ 绑定cpuå’Œéžç»‘定cpu的交互å¼åº”ç”¨ä¹‹é—´çš„äº’åŠ¨ä¹Ÿåº”è¯¥è¢«è€ƒè™‘ï¼Œç‰¹åˆ«æ˜¯å½“å•æ ¸ä½¿ç”¨çŽ‡è¾¾åˆ°100%æ—¶ã€‚å¦‚æžœä½ ç»™äº†è¿™äº›åº”ç”¨ç¨‹åºä¸€åŠçš„cpu-core,并且它们都被安排在åŒä¸€ä¸ªCPU上,ç†è®ºä¸Šéžcpuç»‘å®šçš„åº”ç”¨ç¨‹åºæœ‰ å¯èƒ½åœ¨æŸäº›æ—¶æœŸä½¿ç”¨å¤šè¾¾1msçš„é¢å¤–é…é¢ï¼Œä»Žè€Œé˜»æ¢cpu绑定的应用程åºå®Œå…¨ä½¿ç”¨å…¶é…é¢ï¼Œè¿™ä¹Ÿæ˜¯åŒæ ·çš„æ•° é‡ã€‚在这些情况下,将由CFS算法(è§CFS调度器)æ¥å†³å®šé€‰æ‹©å“ªä¸ªåº”ç”¨ç¨‹åºæ¥è¿è¡Œï¼Œå› 为它们都是å¯è¿è¡Œ 的,并且有剩余的é…é¢ã€‚这个è¿è¡Œæ—¶é—´çš„差异将在接下æ¥çš„交互å¼åº”用程åºç©ºé—²æœŸé—´å¾—到弥补。 例å ---- 1. é™åˆ¶ä¸€ä¸ªç»„çš„è¿è¡Œæ—¶é—´ä¸º1个CPU的价值:: 如果周期是250ms,é…é¢ä¹Ÿæ˜¯250ms,那么该组将æ¯250ms获得价值1个CPUçš„è¿è¡Œæ—¶é—´ã€‚ # echo 250000 > cpu.cfs_quota_us /* quota = 250ms */ # echo 250000 > cpu.cfs_period_us /* period = 250ms */ 2. 在多CPU机器上,将一个组的è¿è¡Œæ—¶é—´é™åˆ¶ä¸º2个CPU的价值 在500ms周期和1000msé…é¢çš„æƒ…况下,该组æ¯500mså¯ä»¥èŽ·å¾—2个CPUçš„è¿è¡Œæ—¶é—´:: # echo 1000000 > cpu.cfs_quota_us /* quota = 1000ms */ # echo 500000 > cpu.cfs_period_us /* period = 500ms */ 这里较大的周期å…è®¸å¢žåŠ çªå‘能力。 3. 将一个组é™åˆ¶åœ¨1个CPUçš„20%。 在50ms周期内,10msé…é¢å°†ç›¸å½“于1个CPUçš„20%。:: # echo 10000 > cpu.cfs_quota_us /* quota = 10ms */ # echo 50000 > cpu.cfs_period_us /* period = 50ms */ 通过在这里使用一个å°çš„周期,我们以牺牲çªå‘容é‡ä¸ºä»£ä»·æ¥ç¡®ä¿ç¨³å®šçš„延迟å“应。 4. 将一个组é™åˆ¶åœ¨1个CPUçš„40%,并å…许累积到1个CPUçš„20%,如果已ç»ç´¯ç§¯äº†çš„è¯ã€‚ 在50ms周期内,20msé…é¢å°†ç›¸å½“于1个CPUçš„40%。而10毫秒的çªå‘将相当于1个 CPUçš„20%:: # echo 20000 > cpu.cfs_quota_us /* quota = 20ms */ # echo 50000 > cpu.cfs_period_us /* period = 50ms */ # echo 10000 > cpu.cfs_burst_us /* burst = 10ms */ 较大的缓冲区设置(ä¸å¤§äºŽé…é¢ï¼‰å…许更大的çªå‘容é‡ã€‚