taskset 入門 - プロセスをCPUコアに固定する

taskset 入門 - プロセスをCPUコアに固定する

この記事で解決できること

  • tasksetプロセスを特定の CPU コアに固定 する方法が分かる
  • 起動時固定(-c実行中プロセスの再割り当て(-p を使い分けられる
  • 性能検証・コア隔離・NUMA で CPU アフィニティを実務で使う型 が身につく

結論(実務の型)

  • 起動時に固定taskset -c 0,1 ./program
  • 実行中プロセスを固定taskset -cp 0-3 <PID>
  • 現状確認taskset -cp <PID>
  • コア番号は -c(リスト形式)が読みやすい。16 進ビットマスクは自動化向け

前提(対象環境)

  • tasksetutil-linux パッケージに含まれる(多くのディストリで標準導入済み)
  • コア番号は 0 始まり。総数は nproc で確認する
  • 実行中プロセスのアフィニティ変更には対象プロセスの権限(または root)が必要

CPU アフィニティとは?

結論: CPU アフィニティとは、プロセスやスレッドを実行できる CPU コアを制限する設定。taskset はこの設定を確認・変更するコマンド。

通常、Linux のスケジューラはプロセスを空いているコアへ自由に動かす。CPU アフィニティを設定すると、そのプロセスは指定したコアの上でしか動かなくなる

固定する主な目的は次の 3 つ。

  • キャッシュ局所性の維持: コア移動で L1/L2 キャッシュが無効化されるのを防ぐ
  • コア隔離: レイテンシ重視のプロセスを専有コアに置き、他プロセスの干渉を避ける
  • 再現性のある性能測定: 毎回同じコアで動かしてベンチマークのブレを減らす

アフィニティは「動けるコアの集合」を指定するもの。1 コアに絞れば固定、複数コアを許可すればその範囲内でスケジューラが選ぶ。

コア数とコア番号を確認する

結論: 固定先を決める前に nproc で利用可能コア数を確認する。コア番号は 0 から始まる。

$ nproc
8

8 と表示されたら、利用可能なコア番号は 07taskset -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 は pspgrep で調べる。

$ 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。0x30b0011 でコア0とコア1、0x80b1000 でコア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

次に読む