4.3. 推奨設定

Red Hat Enterprise Linux ではシステムの設定を行う際に役立つツールがいくつか用意されています。このセクションではこうしたツールを簡単に説明し、Red Hat Enterprise Linux 7 でそのツールを使ってプロセッサー関連の問題を解決する例を紹介します。

4.3.1. カーネルティックタイムの設定

Red Hat Enterprise Linux 7 はデフォルトではティックレスカーネルを使用します。このカーネルは節電のためアイドル状態の CPU には割り込みを行わせないようにして新しいプロセッサーがディープスリープ状態に入れるようにします。
Red Hat Enterprise Linux 7 では動的ティクレスのオプションも用意されています (デフォルトでは無効)。高性能な計算やリアルタイムの計算など待ち時間に厳しい制約のある作業に便利です。
動的ティックレスの動作を特定のコアで有効にするにはカーネルコマンドで nohz_full パラメーターを使ってそのコアを指定します。16 コアシステムなら nohz_full=1-15 と指定すると動的ティックレス動作が 1 から 15 までのコアで有効になり時間管理はすべて未指定のコアに移動されます (コア 0)。この動作は起動時に一時的に有効にすることも /etc/default/grub ファイルで永続的に有効にすることもできます。永続的に有効にする場合は grub2-mkconfig -o /boot/grub2/grub.cfg コマンドを実行して設定を保存します。
動的ティックレス動作を有効にする場合は手作業による管理が必要になります。
  • システムが起動したら手作業で rcu スレッドを待ち時間に制約のないコアに移動します。この場合コア 0 に移動しています。
    # for i in `pgrep rcu[^c]` ; do taskset -pc 0 $i ; done
  • カーネルコマンドラインで isolcpus パラメーターを使って特定のコアをユーザー領域タスクから隔離します。
  • オプションでカーネルの write-back bdi-flush スレッドの CPU 親和性を housekeeping コアに設定することができます。
    echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
動的ティックレス設定が正しく動作しているか次のコマンドを実行して確認します。stress には 1 秒は CPU で実行しているプログラムを入力します。
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
stress の代替のひとつに、while :; do d=1; done 等を実行するスクリプトが考えられます。
デフォルトのカーネルタイマー設定ではビジーな CPU で 1000 ティックになります。
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1000 irq_vectors:local_timer_entry
動的テイクレスカーネルを設定すると 1 ティックになります。
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1 irq_vectors:local_timer_entry

4.3.2. ハードウェアパフォーマンスポリシーの設定 (x86_energy_perf_policy)

x86_energy_perf_policy ツールを使用するとパフォーマンスと電力消費効率のバランスを指定することができます。パフォーマンスまたは電力消費効率どちらをどの程度犠牲にするかのオプションを選択すると、機能に対応するプロセッサーを動作させるためこの情報が使用されます。
デフォルトではツールは全プロセッサー上で performance モードで動作します。プロセッサーのサポートを必要とします。CPUID.06H.ECX.bit3 の表示があればサポートされています。実行する場合は root 権限で行ってください。
x86_energy_perf_policykernel-tools パッケージで提供されます。x86_energy_perf_policy の使い方については「x86_energy_perf_policy」を参照するか man ページをご覧ください。
$ man x86_energy_perf_policy

4.3.3. taskset でプロセスの親和性を設定する

taskset ツールは util-linux パッケージで提供されます。Taskset を使用すると実行中プロセスのプロセッサー親和性を読み出して設定したり、指定プロセッサー親和性でプロセスを起動することができるようになります。

重要

taskset はローカルのメモリー割り当てを保証しません。ローカルメモリー割り当てによりパフォーマンスを向上させる必要がある場合は taskset ではなく numactl を使用することを推奨しています。
taskset の詳細については「taskset」または man ページを参照してください。
$ man taskset

4.3.4. numactl で NUMA 親和性を管理する

numactl を使用すると指定したスケジュールまたはメモリー配置ポリシーでプロセスを実行することができます。Numactl は共有メモリーセグメントやファイルに永続的なポリシーを設定したり、プロセスのプロセッサー親和性やメモリー親和性を設定することもできます。
NUMA トポロジーのシステムではプロセッサーのメモリーへのアクセス速度はプロセッサーとメモリーバンク間の距離が離れるほど低下していきます。したがってパフォーマンス重視のアプリケーションの場合はメモリー割り当てをできるだけ近距離のメモリーバンクから行うよう設定することが重要となります。メモリーと CPU は同じ NUMA ノードのものを使用するのが最適です。
マルチスレッド化したアプリケーションでパフォーマンス重視となるものは特定のプロッセッサーではなく特定の NUMA ノードで実行するよう設定すると効果を得られることがあります。この方法が適切かどうかはご使用のシステムおよびアプリケーションの要件によって異なります。複数のアプリケーションスレッドが同じキャッシュデータにアクセスする場合はスレッドが同じプロセッサーで実行されるよう設定すると良いかもしれません。ただし、別々のデータにアクセスしてキャッシュを行う複数のスレッドが同じプロセッサーで実行される場合、各スレッドは前のスレッドでアクセスされたキャッシュデータ消去する可能性があります。つまり、それぞれのスレッドがキャッシュを「ミス」するため、ディスクからデータを取り出すため実行時間を浪費してキャッシュの入れ替えを行います。キャッシュミスが過剰に発生しているかどうか確認する場合は「perf」の説明に従って perf ツールを使用すると行うことができます。
Numactl はプロセッサーとメモリー親和性を管理する場合に役立つオプションがいくつか用意されています。詳細については「numastat」または man ページをご覧ください。
$ man numactl

注記

numactl パッケージには libnuma ライブラリーが収納され、カーネル対応の NUMA ポリシーに対するシンプルなプログラミングインターフェースを提供しています。numactl アプリケーションに比べより高度な調整を行うことができます。詳細については man ページをご覧ください。
$ man numa

4.3.5. numad を使用した NUMA 親和性の自動管理

numad は自動で NUMA の親和性を管理するデーモンです。NUMA トポロジーとシステム内のリソース使用を監視して NUMA によるリソース管理と管理を動的に改善します。
また、numad では各種のジョブ管理システムによるクエリーに対しそのプロセスに適した CPU とメモリーリソースの初期バインディングを提供するプレプレースメントアドバイスのサービスも用意されています。numad が実行可能ファイルとして実行しているのかサービスとして実行しているのかに関わらずこのプレプレースメントアドバイスを利用することができます。
numad の使い方については「numad」または man ページを参照してください。
$ man numad

4.3.6. スケジューリングポリシーの調整

Linux スケジューラーではスレッドの実行場所と実行期間を決定する数種類のスケジューリングポリシーを実装しています。大きく分けると通常ポリシーとリアルタイムポリシーの 2 種類のカテゴリーに分けられます。通常スレッドは通常の優先度のタスクに使用されます。リアルタイムポリシーは割り込みなしで完了しなければならない時間的制約のあるタスクに使用されます。
リアルタイムスレッドは指定タイムスライスが経過した後もリソースへのアクセスを中断する必要はありません。つまり、ブロックされる、終了する、自発的に停止する、より優先度の高いスレッドが取って代わるなどが起こるまで実行されます。最も優先度の低いリアルタイムスレッドでもノーマルポリシーのスレッドより先にスケジュールされます。

4.3.6.1. スケジューリングポリシー

4.3.6.1.1. SCHED_FIFO を使った静的優先度のスケジューリング
SCHED_FIFO (静的優先度スケジューリングとも呼ばれる) はリアルタイムポリシーで各スレッドに固定の優先度を指定します。このポリシーを使用するとイベントの応答時間を改善し待ち時間を低減させることができるため、長期間は実行しない時間的制約のあるタスク対しての使用が推奨されます。
SCHED_FIFO を使用すると、スケジューラーは SCHED_FIFO 全スレッドの一覧を優先度順にスキャンし実行準備ができているスレッドで最も順位が高いスレッドをスケジュールに入れます。SCHED_FIFO スレッドの優先レベルは 1 から 99 で指定することができ、99 が最も高い優先度になります。Red Hat では最初は低い順位で使用を開始し、待ち時間に関する問題が見つかった場合にのみ徐々に優先度を上げていく方法を推奨しています。

警告

リアルタイムスレッドはタイムスライスに依存しないため、Red Hat では優先度 99 の設定は推奨していません。この優先度を使用するとプロセスは移行スレッドや監視スレッドと同じ優先レベルにすることになってしまいます。このスレッドが演算ループに陥りブロックされるとスレッドの実行は不可能になります。プロセッサーがひとつのシステムの場合は最終的にハングすることになります。
管理者側で SCHED_FIFO の帯域幅を制限してリアルタイムのアプリケーションプログラマーがプロセッサーを独占するリアルタイムのタスクを開始しないよう阻止することができます。
/proc/sys/kernel/sched_rt_period_us
上記のパラメーターはプロセッサー帯域幅の 100% とみなされるべき時間をマイクロ秒で定義します。デフォルト値は 1000000 μs もしくは 1 秒です。
/proc/sys/kernel/sched_rt_runtime_us
上記のパラメーターはリアルタイムスレッドの実行に当てられる時間をマイクロ秒で定義します。デフォルト値は 950000 μs もしくは 0.95 秒です。
4.3.6.1.2. SCHED_RR を使ったラウンドロビン方式の優先度スケジューリング
SCHED_RRSCHED_FIFO のラウンドロビン版になります。複数のスレッドを同じ優先レベルで実行しなければならない場合に便利です。
SCHED_FIFO と同様、SCHED_RR は各スレッドに固定の優先度を指定するリアルタイムポリシーになります。スケジューラーは SCHED_RR 全スレッドの一覧を優先度順にスキャンし実行準備ができているスレッドで最も優先順位が高いスレッドをスケジュールに入れます。ただし、SCHED_FIFO とは異なり複数のスレッドが同じ優先度を持つ場合は特定の時間内でラウンドロビン方式にスケジュールが行われます。
この時間枠は sched_rr_timeslice_ms カーネルパラメーターを使って秒単位で設定することができます (/proc/sys/kernel/sched_rr_timeslice_ms)。最も小さい値は 1 ミリ秒になります。
4.3.6.1.3. SCHED_OTHER を使った通常のスケジュール
Red Hat Enterprise Linux 7 では SCHED_OTHER がデフォルトのスケジューリングポリシーになります。CFS (Completely Fair Scheduler) を使ってこのポリシーでスケジュールされているスレッドすべてに対してプロセッサーへの公平なアクセスを提供します。多量のスレッドやデータの処理が重要な場合にはこのポリシーの方が長い期間で見ると効率的なスケジュールになります。
このポリシーを使用するとスケジューラーは各プロセススレッドの niceness 値に基づいて動的な優先リストを作成します。管理者側でプロセスの niceness 値を変更することはできますがスケジューラーの動的な優先リストを直接変更することはできません。
プロセスの niceness を変更する方法については https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/ にある『Red Hat Enterprise Linux 7 システム管理者のガイド』を参照してください。

4.3.6.2. CPU の分離

isolcpus 起動パラメーターを使用するとスケジューラーから CPU を切り離すことができます。これによりスケジューラーがその CPU 上にあるユーザー領域のスレッドをスケジュールしないよう保護します。
CPU を分離させた場合は CPU 親和性のシステムコールか numactl コマンドを使ってその CPU に手動でプロセスを割り当てなければなりません。
3 番目の CPU と6 番目から 8 番目の CPU を分離させる場合は以下をカーネルのコマンドラインに追加します。
isolcpus=2,5-7
また CPU の分離は Tuna ツールを使っても行うことができます。Tuna を使用すると起動時だけでなくいつでも CPU の分離を行うことができます。この方法は isolcpus パラメーターを使用する場合とは若干異なり、isolcpus で得られるようなパフォーマンスの改善は現時点では期待できません。ツールの詳細については「Tuna を使った CPU、スレッド、割り込みの親和性などの設定」を参照してください。

4.3.7. 割り込みの親和性の設定

割り込み要求には関連づけられた親和性プロパティー smp_affinity があり、割り込み要求を処理するプロセッサーはこのプロパティーによって指定されます。アプリケーションのパフォーマンスを改善するには割り込みの親和性とプロセスの親和性を同じプロセッサーまたは同じコアにある複数のプロセッサーに割り当てます。これにより指定した割り込みとアプリケーションスレッドがキャッシュラインを共有できるようになります。
特定の割り込み要求の割り込み親和性の値は該当の /proc/irq/irq_number/smp_affinity ファイルに格納されます。smp_affinity はシステム内の全プロセッサーを表す 16 進数のビットマスクで保存されます。デフォルト値は f でシステム内のどのプロセッサーでも割り込み要求を処理できるという意味になります。この値を 1 に設定すると割り込み要求を処理できるのはプロセッサー 0 のみになります。
プロセッサーが 32 以上搭載されているシステムでは 32 ビットグループそれぞれに smp_affinity 値を区切って設定する必要があります。例えば、64 プロセッサーシステムの最初の 32 プロセッサーにのみ割り込み要求の処理を行わせたい場合は以下を実行します。
# echo 0xffffffff,00000000 > /proc/irq/IRQ_NUMBER/smp_affinity
代わりに、BIOS が NUMA トポロジーをエクスポートする場合は irqbalance サービスにその情報を使用させサービスを要求しているハードウェアに対してローカルとなるノードで割り込み要求を処理させることもできます。irqbalance の詳細については「irqbalance」を参照してください。

注記

割り込みステアリングに対応するシステムの場合は割り込み要求の smp_affinity を修正するとハードウェアが設定され、カーネルを介入させることなくハードウェアレベルで特定プロセッサーに割り込みを処理させる決定が行われるようになります。割り込みステアリングについては「7章ネットワーク」を参照してください。

4.3.8. Tuna を使った CPU、スレッド、割り込みの親和性などの設定

Tuna を使用すると CPU、スレッド、割り込みの親和性などを管理し、管理対象となるエンティティのタイプに合わせた各種動作を行うことができます。Tuna の全機能については「Tuna」を参照してください。
指定 CPU (複数可) から全スレッドを切り離すには次のコマンドを実行します。CPUs には分離させる CPU 番号を入力します。
# tuna --cpus CPUs --isolate
特定スレッドの実行が可能 CPU 一覧に任意の CPU を含ませるには次のコマンドを実行します。CPUs には含ませる CPU 番号を入力します。
# tuna --cpus CPUs --include
割り込み要求を指定 CPU に移動させるには次のコマンドを入力します。CPUs には CPU 番号、IRQs には移動させる割り込み要求をコンマで区切って入力します。
# tuna --irqs IRQs --cpus CPU --move
代わりに次のコマンドを使ってパターン sfc1* の全割り込み要求を検索することもできます。
# tuna -q sfc1* -c7 -m -x
スレッドのポリシーと優先度を変更するには次のコマンドを実行します。thread には変更するスレッド、policy にはスレッドに適用するポリシー名、level には 0 (最も低い優先度) から 99 (最も高い優先度) の整数をそれぞれ入力します。
# tuna --threads thread --priority policy:level