![](/img/trans.png)
[英]Linux kernel - How CPU subsystem(of CGROUPS) different from CPU scheduler?
[英]how to shield a cpu from the linux scheduler (prevent it scheduling threads onto that cpu)?
可以使用sched_setaffinity
將線程固定到cpu,從而提高性能(在某些情況下)
從linux手冊頁:
限制在單個CPU上運行的進程還可以避免在進程停止在一個CPU上執行然后重新開始在另一個CPU上執行時發生的高速緩存失效導致的性能成本
此外,如果我希望獲得更實時的響應,我可以將該線程的調度程序策略更改為SCHED_FIFO
,並將優先級更高為某個高值(最多為sched_get_priority_max
),這意味着所討論的線程應始終優先於其他任何其他線程。線程在准備就緒時在其cpu上運行。
但是,此時,在實時線程剛剛搶占的cpu上運行的線程可能已經驅逐了大部分實時線程的一級緩存條目。
我的問題如下:
答案是使用cpusets 。 python cpuset實用程序可以輕松配置它們。
基本概念
3個cpusets
root
:存在於所有配置中並包含所有cpus( 非屏蔽 ) system
:包含用於系統任務的cpus - 需要運行但不“重要”的( 非屏蔽 ) user
:包含用於“重要”任務的cpus - 我們想要以“實時”模式運行的那些( 屏蔽 ) shield
命令管理這3個cpusets。
在設置過程中,它將所有可移動任務移動到未屏蔽的cpuset( system
)中,在拆解過程中,它將所有可移動任務移動到root
cpuset中。 設置完成后,子命令允許您將任務移動到shield ( user
)cpuset中,此外,還可以將特殊任務(內核線程)從root
到system
(因此也可以移出user
cpuset)。
命令:
首先,我們創建一個盾牌。 當然,屏蔽的布局將取決於機器/任務。 例如,假設我們有一個4核非NUMA機器:我們希望將3個核心專用於屏蔽 ,並為不重要的任務留下1個核心 ; 因為它是非NUMA,我們不需要指定任何內存節點參數,我們讓內核線程在root
cpuset中運行(即:跨所有cpu)
$ cset shield --cpu 1-3
某些內核線程(未綁定到特定cpu的線程)可以移動到system
cpuset中。 (一般來說,移動已綁定到特定cpu的內核線程並不是一個好主意)
$ cset shield --kthread on
現在讓我們列出屏蔽( user
)或非屏蔽( system
)cpusets中正在運行的內容:( -v
表示詳細信息,將列出進程名稱)(添加第二個-v
以顯示超過80個字符)
$ cset shield --shield -v
$ cset shield --unshield -v -v
如果我們想要停止盾牌(拆解)
$ cset shield --reset
現在讓我們在屏蔽中執行一個進程( '--'
后面'--'
命令被傳遞給要執行的命令,而不是cset
)
$ cset shield --exec mycommand -- -arg1 -arg2
如果我們已經有一個正在運行的進程,我們想要移動到屏蔽中(注意我們可以通過傳遞逗號分隔列表或范圍來移動多個進程(范圍中的任何進程都將被移動,即使存在間隙))
$ cset shield --shield --pid 1234
$ cset shield --shield --pid 1234,1236
$ cset shield --shield --pid 1234,1237,1238-1240
先進的理念
cset set/proc
- 這些可以讓你更好地控制cpusets
組
創建,調整,重命名,移動和銷毀cpusets
命令
使用cpus 1-3創建一個cpuset,使用NUMA節點1並將其命名為“my_cpuset1”
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
將“my_cpuset1”更改為僅使用cpus 1和3
$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1
銷毀cpuset
$ cset set --destroy --set=my_cpuset1
重命名現有的cpuset
$ cset set --set=my_cpuset1 --newname=your_cpuset1
創建分層cpuset
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
列出現有的cpusets(1級深度)
$ cset set --list
列出現有的cpuset及其子代
$ cset set --list --set=my_cpuset1
列出所有現有的cpusets
$ cset set --list --recurse
PROC
管理線程和流程
命令
列出在cpuset中運行的任務
$ cset proc --list --set=my_cpuset1 --verbose
在cpuset中執行任務
$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2
移動任務
$ cset proc --toset=my_cpuset1 --move --pid 1234
$ cset proc --toset=my_cpuset1 --move --pid 1234,1236
$ cset proc --toset=my_cpuset1 --move --pid 1238-1340
移動任務及其所有兄弟姐妹
$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads
將所有任務從一個cpuset移動到另一個cpuset
$ cset proc --move --fromset=my_cpuset1 --toset=system
將未固定的內核線程移動到cpuset中
$ cset proc --kthread --fromset=root --toset=system
強制將內核線程(包括固定到特定cpu的線程)移動到cpuset中(注意:這可能會給系統帶來可怕的后果 - 確保你知道你在做什么)
$ cset proc --kthread --fromset=root --toset=system --force
層次結構示例
我們可以使用分層cpusets來創建優先級分組
system
cpuset prio_low
cpuset(1) prio_met
cpuset prio_high
cpuset(1-3) prio_all
cpuset(注意這與root相同;保持與root分離是個好習慣) 要實現上述目的,請創建prio_all,然后在prio_all等下創建子集prio_high
$ cset set --cpu=0 --set=system
$ cset set --cpu=0-3 --set=prio_all
$ cset set --cpu=1-3 --set=/prio_all/prio_high
$ cset set --cpu=1-2 --set=/prio_all/prio_high/prio_med
$ cset set --cpu=1 --set=/prio_all/prio_high/prio_med/prio_low
還有另外兩種方法我可以想到這樣做(雖然不像cset那樣優雅,但似乎沒有Redhat提供的出色支持):
1)任務集包括PID 1在內的所有內容 - 簡單易行(但是,alledgly - 我自己從未見過任何問題 - 可能會導致調度程序效率低下)。 下面的腳本(必須以root身份運行)在所有正在運行的進程上運行taskset,包括init(pid 1); 這會將所有正在運行的進程固定到一個或多個“垃圾核心”,並且通過固定init,它將確保任何未來的進程也在“垃圾核心”列表中啟動:
#!/bin/bash
if [[ -z $1 ]]; then
printf "Usage: %s '<csv list of cores to set as junk in double quotes>'", $0
exit -1;
fi
for i in `ps -eLfad |awk '{ print $4 } '|grep -v PID | xargs echo `; do
taskset -pc $1 $i;
done
2)使用isolcpus內核參數(這里是https://www.kernel.org/doc/Documentation/kernel-parameters.txt中的文檔):
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler.
Format:
<cpu number>,...,<cpu number>
or
<cpu number>-<cpu number>
(must be a positive range in ascending order)
or a mixture
<cpu number>,...,<cpu number>-<cpu number>
This option can be used to specify one or more CPUs
to isolate from the general SMP balancing and scheduling
algorithms. You can move a process onto or off an
"isolated" CPU via the CPU affinity syscalls or cpuset.
<cpu number> begins at 0 and the maximum value is
"number of CPUs in system - 1".
This option is the preferred way to isolate CPUs. The
alternative -- manually setting the CPU mask of all
tasks in the system -- can cause problems and
suboptimal load balancer performance.
我已經將這兩個加上cset機制用於幾個項目(順便說一句,請原諒明顯的自我推銷:-)),我剛剛為一個名為Pontus Vision ThreadManager的工具提交了一項專利,該工具為任何項目提供了最佳的固定策略給予x86平台任何給定的軟件工作負載; 在客戶站點測試之后,我得到了非常好的結果(峰值延遲減少了270%),因此非常值得進行固定和CPU隔離。
以下是使用cgroups以傳統方式進行的操作。 我有一台Fedora 28機器,RedHat / Fedora希望你使用systemd-run
,但我無法在那里找到這個功能。 我很想知道如何使用systemd-run
來做,如果有人願意開導我的話。
假設我想從調度中排除我的第四個CPU(CPU 0-3),並將所有現有進程移到CPU 0-2。 然后我想自己在CPU 3上放一個進程。
sudo su -
cgcreate -g cpuset:not_cpu_3
echo 0-2 > /sys/fs/cgroup/cpuset/not_cpu_3/cpuset.cpus
# This "0" is the memory node. See https://utcc.utoronto.ca/~cks/space/blog/linux/NUMAMemoryInfo
# for more information *
echo 0 > /sys/fs/cgroup/cpuset/not_cpu_3/cpuset.mems
/proc/zoneinfo
和/sys/devices/system/node
heirarchy。 獲取正確的節點信息留給讀者練習。 現在我們有了cgroup,我們需要創建我們的隔離CPU 3 cgroup:
cgcreate -g cpuset:cpu_3
echo 3 > /sys/fs/cgroup/cpuset/cpu_3/cpuset.cpus
# Again, the memory node(s) you want to specify.
echo 0 > /sys/fs/cgroup/cpuset/cpu_3/cpuset.mems
將所有進程/線程放在not_cpu_3
cgroup上:
for pid in $(ps -eLo pid) ; do cgclassify -g cpuset:not_cpu_3 $pid; done
評論:
ps -eL k psr o psr,pid,tid,args | sort | cut -c -80
注意! 目前處於睡眠狀態的進程不會移動 。 必須喚醒它們,以便調度程序將它們放在不同的CPU上。 要看到這一點,請在上面的列表中選擇您最喜歡的休眠過程 - 您認為應該在CPU 0-2上的過程,例如Web瀏覽器,但它仍然在3上。使用上面列表中的線程ID,執行:
kill -CONT <thread_id>
例
kill -CONT 9812
重新運行ps命令,並注意它已移動到另一個CPU。
雙注! 一些內核線程不能也不會移動! 例如,您可能會注意到每個CPU上都有一個內核線程[kthreadd]
。 將進程分配給cgroup適用於用戶空間進程,而不適用於內核線程。 這是多任務世界的生活。
現在將進程及其所有子進程移動到控制組cpu_3:
pid=12566 # for example
cgclassify -g cpuset:cpu_3 $pid
taskset -c -p 3 $pid
同樣,如果$pid
正在休眠,你需要將其喚醒,以便實際進行CPU移動。
要撤消所有這些操作,只需刪除您創建的cgroup即可。 每個人都會被卡回到根cgroup:
cgdelete -r cpuset:cpu_3
cgdelete -r cpuset:not_cpu_3
無需重啟。
(對不起,我不明白原帖中的第3個問題。我不能對此發表評論。)
如果你正在使用rhel實例,你可以使用Tuna(也可以用於其他Linux發行版,但不確定)。 它可以從yum命令輕松安裝。 Tuna可用於隔離cpu核心,它可以動態地將在該特定cpu中運行的進程移動到相鄰的cpu。 隔離cpu核心的命令如下,
# tuna --cpus=CPU-LIST --isolate
您可以使用htop
查看金槍魚如何實時隔離cpu核心。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.