答えは、cpuset を使用することです。 python cpuset ユーティリティを使用すると、それらを簡単に構成できます。
基本概念
3 CPU セット
root
:すべての構成に存在し、すべての CPU を含みます (unshielded )system
:システム タスクに使用される cpus を含みます - 実行する必要があるが「重要」ではないもの (unshielded) )user
:「重要な」タスクに使用される CPU が含まれています - 「リアルタイム」モードで実行したいタスク (Shielded )
shield
コマンドはこれら 3 つの cpuset を管理します。
セットアップ中に、すべての可動タスクをシールドされていない cpuset (system
) に移動します。 ) 分解中に、移動可能なすべてのタスクを root
に移動します。 cpuset.セットアップ後、サブコマンドを使用してタスクをシールドに移動できます (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
詳細な場合、プロセス名がリストされます) (2 番目の -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
- これらにより、CPU セットをより細かく制御できます
セット
cpuset の作成、調整、名前変更、移動、破棄
コマンド
cpuset を作成し、cpus 1 ~ 3 を使用し、NUMA ノード 1 を使用して「my_cpuset1」と呼びます
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
CPU 1 と 3 のみを使用するように「my_cpuset1」を変更
$ 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
階層型 CPU セットを作成する
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
既存の cpuset を一覧表示します (レベル 1 の深さ)
$ cset set --list
既存の cpuset とその子を一覧表示
$ cset set --list --set=my_cpuset1
既存のすべての cpuset を一覧表示
$ cset set --list --recurse
手続き
スレッドとプロセスを管理する
コマンド
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
すべてのタスクを 1 つの 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
階層の例
階層型 cpuset を使用して、優先グループを作成できます
<オール>system
を作成する 1 cpu (0) の cpusetprio_low
を作成する cpuset と 1 cpu (1)prio_met
を作成する 2 つの CPU を持つ cpuset (1-2)prio_high
を作成する 3 つの CPU を持つ cpuset (1-3)prio_all
を作成する 4 つのすべての cpus (0-3) を持つ cpuset (これはルートと同じであることに注意してください。ルートから分離しておくことをお勧めします)上記を実現するには、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
これを行うには他に 2 つの方法が考えられます (ただし、cset ほどエレガントではなく、Redhat からの素晴らしいレベルのサポートはないようです):
1) PID 1 を含むすべてのタスクセット - 素晴らしく簡単です (しかし、伝えられるところでは - 私自身は問題を見たことがありません - スケジューラーで非効率を引き起こす可能性があります)。以下のスクリプト (root として実行する必要があります) は、init (pid 1) を含むすべての実行中のプロセスでタスクセットを実行します。これにより、実行中のすべてのプロセスが 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.
私はいくつかのプロジェクトでこれらの 2 つと cset メカニズムを使用しました (ちなみに、露骨な自己宣伝を許してください :-))。特定の x86 プラットフォームを任意のソフトウェア作業負荷に。お客様のサイトでテストしたところ、非常に良い結果 (ピーク レイテンシが 270% 削減) が得られたので、ピニングと CPU の分離を行う価値は十分にあります。