tasksetやnumactlを使ってプロセスが動くCPUコアを指定する

2017/06/15

Redisのようにシングルコアで動かすものをtasksetコマンドでCPUのコアを固定することでパフォーマンスが向上する場合がある。

CPUが2コアあるとして、1コア目がネットワーク通信に使用されているとき、Redisまで1コア目で動くと、通信とRedisプロセスがCPUを奪い合うことになるので、Redisを2コア目で動くようにする。
HAProxy Enterprise Editionのドキュメントにも同様の記載がある。

For high performance purpose, it is required to stick network IOs and some processes on different CPU cores.

tasksetの概要については、RedHatのパフォーマンスチューニングガイド_4.1.2. CPU パフォーマンスのチューニングの「4.1.2.1. taskset を使った CPU アフィニティの設定」やRedHatのリファレンスガイド_第6章 親和性に記載の通り。
4.1.2. CPU パフォーマンスのチューニング

taskset は、実行中のプロセスの CPU アフィニティを (プロセス ID で) 取得、設定します。特定の CPU アフィニティを使ってプロセスを開始することも可能で、この場合はこの指定されたプロセスは特定の CPU または CPU セットにバインドされます。

第6章 親和性

効率的なポリシーと優先度の設定と共に、プロセッサー親和性も設定すると最大限可能なパフォーマンスを得ることができます。 アプリケーションは常に他のプロセスと特に CPU タイムなどのリソースを獲得するため競争しなければならなくなります。 アプリケーションによっては複数の関連スレッドが同じコアで実行されることがよくあります。 代わりにひとつのアプリケーションスレッドをひとつのコアに割り当てることができます。
(中略)
また、任意の CPU から別の CPU にプロセスを移行することは、キャッシュが無効化するためコスト高となる場合があります。

親和性、アフィニティ(affinity)という言葉が良く登場するが、これはプロセッサーコアとプロセスとの結びつきのこと。

以下の各種指定方法で設定できる。

commandの前に--が指定されているのはcommandがオプション引数をとる場合、tasksetの引数とみなされないように、オプション引数が--以降無いということを示している。
ただ、tasksetには以下の注意点があるため、numactlの使用も検討が必要。

taskset はローカルメモリの割り当てを保証するわけではありません。ローカルメモリの割り当てによるパフォーマンスの向上を必要とする場合は、taskset ではなく numactl を使用することが推奨されます。

NUMA(Non-Uniform Memory Access、ヌマ)とは、プロセッサーパッケージごとにメモリーコントローラーがあり、そこにメモリーが接続されているアーキテクチャのことを言うが、その説明は、Non-Uniform Memory Access についての一節がわかりやすい。

最近のハードウェア面の傾向として、それぞれがプロセッサの小さなセットとして機能するシステム バスが複数搭載されるようになりました。プロセッサの各グループには専用のメモリが搭載されており、場合によっては専用の I/O チャネルが搭載されている場合もあります。ただし、各 CPU は他のグループに関連付けられているメモリには、一貫した方法でアクセスできます。この CPU の各グループのことを NUMA ノードと呼びます。NUMA ノード内の CPU 数は、ハードウェア ベンダにより異なります。ノードのローカル メモリにアクセスする方が、他の NUMA ノードに属するメモリにアクセスするよりも高速です。このようにアクセス速度が一定ではないことから、NUMA (non-uniform memory access : 非均質メモリ アクセス) アーキテクチャと呼ばれています。

numactlについては、実アプリケーションの最適化のテクニックがわかりやすい。

またnumactlを利用する方法の利点は、NUMAアーキテクチャを意識せずに作成されている(CPU、メモリの明示的割り当てを行っていない)プログラムを実行する際に、実行段階でCPUへの割りつけやメモリ割り当てを指定できるということです。よって既存アプリケーションを主に利用しているユーザも、NUMAアーキテクチャを意識することで今までよりも高速にプログラムが実行される可能性が出てきます。

CPUについては、使用するCPUをコアの単位で指定する—physcpubind=cpusオプションや、使用するCPUをノード単位(※NUMAはCPUとローカルメモリのセットをノードという単位で表す)で指定する—cpunodebind=nodesオプション等がある。
メモリについては、指定したノードのメモリに均等にデータを分割して保存する—interleave=nodesオプション、使用するメモリをノード単位で指定する—membind=nodesオプションがある。
以下のようにコマンドを指定のCPUコアとメモリ起動する。

その他参考
NUMAとnumactlの説明
マルチコアCPUを賢く使いこなす スケジューリングの秘密

-Linux
-