taskset 入門 - プロセスをCPUコアに固定する
この記事で解決できること
tasksetで プロセスを特定の CPU コアに固定 する方法が分かる- 起動時固定(
-c) と 実行中プロセスの再割り当て(-p) を使い分けられる - 性能検証・コア隔離・NUMA で CPU アフィニティを実務で使う型 が身につく
結論(実務の型)
- 起動時に固定 →
taskset -c 0,1 ./program - 実行中プロセスを固定 →
taskset -cp 0-3 <PID> - 現状確認 →
taskset -cp <PID> - コア番号は
-c(リスト形式)が読みやすい。16 進ビットマスクは自動化向け
前提(対象環境)
tasksetはutil-linuxパッケージに含まれる(多くのディストリで標準導入済み)- コア番号は 0 始まり。総数は
nprocで確認する - 実行中プロセスのアフィニティ変更には対象プロセスの権限(または
root)が必要
CPU アフィニティとは?
結論: CPU アフィニティとは、プロセスやスレッドを実行できる CPU コアを制限する設定。
tasksetはこの設定を確認・変更するコマンド。
通常、Linux のスケジューラはプロセスを空いているコアへ自由に動かす。CPU アフィニティを設定すると、そのプロセスは指定したコアの上でしか動かなくなる。
固定する主な目的は次の 3 つ。
- キャッシュ局所性の維持: コア移動で L1/L2 キャッシュが無効化されるのを防ぐ
- コア隔離: レイテンシ重視のプロセスを専有コアに置き、他プロセスの干渉を避ける
- 再現性のある性能測定: 毎回同じコアで動かしてベンチマークのブレを減らす
アフィニティは「動けるコアの集合」を指定するもの。1 コアに絞れば固定、複数コアを許可すればその範囲内でスケジューラが選ぶ。
コア数とコア番号を確認する
結論: 固定先を決める前に
nprocで利用可能コア数を確認する。コア番号は0から始まる。
$ nproc
8
8 と表示されたら、利用可能なコア番号は 0〜7。taskset -c 8 ... のように存在しないコアを指定するとエラーになる。
物理/論理構成まで見たい場合は lscpu を併用する。
$ lscpu
起動時にコアを固定する(-c)
結論: コマンド起動と同時に固定するなら
taskset -c <コアリスト> <コマンド>。リスト形式は0,2(個別)や0-3(範囲)で書ける。
新しくプロセスを起動して、最初から特定コアに固定する基本形。
# コア0と1だけで program を起動 $ taskset -c 0,1 ./program # コア0〜3の範囲で起動 $ taskset -c 0-3 ./program # 単一コア(コア2)に完全固定 $ taskset -c 2 ./program
-c(--cpu-list)はコア番号をそのまま列挙できるので読みやすい。, で個別指定、- で範囲指定、両者の併用も可能(例: 0,2,4-7)。
起動するコマンドにオプションを渡す場合は、そのまま後ろに続ける。
taskset -c 0,1 stress-ng --cpu 2 のように -- で区切る必要はない。
実行中プロセスのアフィニティを確認・変更する(-p)
結論: すでに動いているプロセスは
-p(--pid)で操作する。taskset -cp <PID>で確認、taskset -cp <コアリスト> <PID>で変更。
現在のアフィニティを確認する
$ taskset -cp 1234
pid 1234's current affinity list: 0-7
0-7 は「全コアで動ける」状態(デフォルト)。-c を付けるとコアリスト形式、付けないと 16 進マスクで表示される。
実行中プロセスを再割り当てする
# PID 1234 をコア0,1に再割り当て $ taskset -cp 0,1 1234
pid 1234's current affinity list: 0-7 pid 1234's new affinity list: 0,1
PID は ps や pgrep で調べる。
$ pgrep -f program
引数の順序に注意
-p モードでは コアリストが先、PID が後。taskset -cp 0,1 1234 であって、taskset -cp 1234 0,1 ではない。順序を逆にすると PID をマスクとして解釈し失敗する。
16 進ビットマスクとリスト形式の違い
結論:
-cを付けるとコア番号リスト、付けないと 16 進ビットマスク。マスクは各ビットが 1 コアに対応する(bit0=コア0)。
taskset は本来 16 進のビットマスクでコアを指定する。-c はそれを人間が読みやすいリスト形式に置き換えるオプション。
| 指定したいコア | リスト形式(-c) | 16 進マスク |
|---|---|---|
| コア0 | 0 |
0x1 |
| コア0,1 | 0,1 |
0x3 |
| コア1のみ | 1 |
0x2 |
| コア0〜3 | 0-3 |
0xf |
| コア3のみ | 3 |
0x8 |
マスクは 2 進で考えると分かりやすい。最下位ビット(右端)がコア0。0x3 は 0b0011 でコア0とコア1、0x8 は 0b1000 でコア3を表す。
# マスク形式での起動(コア0,1 = 0x3) $ taskset 0x3 ./program # マスク形式での確認(-c なし) $ taskset -p 1234
pid 1234's current affinity mask: ff
手で書くなら リスト形式(-c)が安全。マスクは桁を間違えると別のコアを指してしまう。スクリプトで機械生成する場合のみマスクが有利。
全スレッドに適用する(-a)
結論: マルチスレッドプロセスで全スレッドを固定するには
-a(--all-tasks)を併用する。省略すると主スレッドのみが対象。
-p で実行中プロセスを操作する際、デフォルトでは指定 PID(主スレッド)だけにアフィニティが適用され、既存の子スレッドには波及しない。プロセス内の全スレッドをまとめて固定するには -a を付ける。
# PID 1234 の全スレッドをコア0-3に固定 $ taskset -acp 0-3 1234
-a を付けても、変更後に新しく生成されたスレッド はそのプロセスのアフィニティを継承する。既存スレッドへの一括適用が -a の役割であり、将来のスレッドは元々継承される点を混同しないこと。
実務での使いどころ
結論: 性能測定の再現性確保、レイテンシ重視プロセスのコア隔離、NUMA でのローカルメモリ最適化が代表的なユースケース。
ベンチマークの再現性を上げる
毎回同じコアで測ることで、コア間移動によるキャッシュミスのばらつきを排除する。
$ taskset -c 2,3 ./benchmark
レイテンシ重視プロセスを隔離する
カーネル起動パラメータ isolcpus で OS スケジューラから隔離したコアに、taskset で目的プロセスだけを載せる運用と組み合わせる。
NUMA でローカルメモリに寄せる
NUMA 環境では、メモリと同じノードのコアに固定するとリモートメモリアクセスを避けられる。ただしメモリ割り当ても制御したい場合は numactl の方が適している(taskset は CPU 配置のみ)。
過剰固定の落とし穴
固定しすぎると、空いている他コアを使えずかえって遅くなることがある。固定は「測定して効果を確認してから」。やみくもに固定しない。
よくあるエラーと対処
結論: 多くは「存在しないコア番号」「権限不足」「引数順の誤り」のいずれか。
sched_setaffinity: Invalid argument
存在しないコア番号を指定している。nproc で範囲を確認する。
# コアが8個(0-7)しかないのにコア8を指定 → エラー $ taskset -c 8 ./program
Operation not permitted
他ユーザーのプロセスを変更しようとしている。対象プロセスの所有者で実行するか sudo を使う。
$ sudo taskset -cp 0,1 1234
command not found: taskset
util-linux が入っていない(最小構成のコンテナ等)。Debian/Ubuntu なら以下で導入する。
$ sudo apt install util-linux