簡體   English   中英

如何從linux調度程序屏蔽cpu(防止它將線程調度到該cpu)?

[英]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上運行的線程可能已經驅逐了大部分實時線程的一級緩存條目。

我的問題如下:

  1. 是否可以阻止調度程序將任何線程調度到給定的cpu上? (例如:要么完全從調度程序中隱藏cpu,要么以其他方式)
  2. 是否有一些線程絕對必須能夠在該CPU上運行? (例如:內核線程/中斷線程)
  3. 如果我需要在該cpu上運行內核線程,那么使用什么是合理的最大優先級值,這樣我就不會匱乏內核線程?

答案是使用cpusets python cpuset實用程序可以輕松配置它們。

基本概念

3個cpusets

  • root :存在於所有配置中並包含所有cpus( 非屏蔽
  • system :包含用於系統任務的cpus - 需要運行但不“重要”的( 非屏蔽
  • user :包含用於“重要”任務的cpus - 我們想要以“實時”模式運行的那些( 屏蔽

shield命令管理這3個cpusets。

在設置過程中,它將所有可移動任務移動到未屏蔽的cpuset( system )中,在拆解過程中,它將所有可移動任務移動到root cpuset中。 設置完成后,子命令允許您將任務移動到shielduser )cpuset中,此外,還可以將特殊任務(內核線程)從rootsystem (因此也可以移出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來創建優先級分組

  1. 用1 cpu(0)創建一個system cpuset
  2. 使用1個cpu創建一個prio_low cpuset(1)
  3. 用2 cpus(1-2)創建一個prio_met cpuset
  4. 用3 cpus創建一個prio_high cpuset(1-3)
  5. 創建一個包含全部4個cpus(0-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM