C言語

【C言語】sched_setaffinity関数の使い方、正しいですか?

2022年3月21日

関数仕様

書式

引数

pid プロセスの PID、スレッドの thread id、または 0(呼び出し元スレッド)
cpusetsize mask が指すデータ長 (バイト)。通常は sizeof(cpu_set_t) を指定
mask CPU affinity を指定する mask(CPUコア番号の集合)
cpu CPU のコア番号
set mask をセット・チェックする cpu_set_t へのポインタ

戻り値

0 正常に完了
-1 エラーが発生(errno にエラー番号がセットされています)

代表的なエラー

  • EPERM
    呼び出し元のスレッドに適切な権限がない
  • ESRCH
    pid が指すスレッドが見つからない

 

機能

  • sched_setaffinity
    スレッドの実行を許可する CPU affinity(親和度)マスクを設定する
  • sched_getaffinity
    スレッドに設定されている CPU affinity マスクを取得する

メリット

  1. スレッドの実行速度を最大化
    特定のスレッドを1つのCPUコアに割り当てることにより、
    確実にそのスレッドの実行速度を最大にすることができます
  2. CPUのキャッシュ無効化を抑止
    実行したスレッドが前回と異なる CPU で実行される場合、キャッシュが無効化されます
    実行する CPU を固定とすることで、キャッシュ無効化による性能劣化を防げます

 

CPU affinity マスクは「CPU 集合」を表す cpu_set_t で表現され、そのポインタで mask を指定します。
CPU 集合を操作するために、CPU_CLR, CPU_ISSET, CPU_SET, CPU_ZERO のマクロ群を使用します。

SANACHAN
SANACHAN
cpu_set_t 構造体は、CPUコアを BIT で表現したものです。

 

sched_setaffinity
スレッド ID が 0 の場合、呼び出し元スレッドに設定されます。
指定したスレッドが mask で指定された CPU のいずれかで現在実行されていない場合、
そのスレッドは mask で指定された CPU へ即座に移動されます。

sched_getaffinity
スレッド ID が pid のスレッドの affinity マスクを mask へ書き込みます。

 

注意すること

注意ポイント①

スレッドを特定の CPU に割り当て固定するだけでは、実行性能を最大化できない

sched_setaffinity の man ページにも記載されていますが、特定のスレッドの実行性能を最大化したい場合、
その他のスレッド全てに割り当てたい CPU 以外のマスクを設定する必要があります

例えば、CPUコアが2つある場合で、スレッドA に CPU1 を固定的に割り当てたい場合、
その他の全てのスレッドに CPU0 を割り当てる必要があります。
これには、Kernel の割り込みスレッド、Kernel スレッドを含みます

そうしないと、他のスレッドは CPU0 と CPU1 を自由に使える状態ですが、
スレッドA は CPU1 しか使えなくなり、かえって性能が悪くなってしまいます

SANACHAN
SANACHAN
Linux Kernel の標準的なスケジューラは、shell のようなたまにしか動かないスレッドの優先度を上げる場合があります。忙しく動いているスレッドの優先度を下げ、shell が動けるようにすることが目的です。
そのため、スレッドA に設定するだけでは、別のスレッドに簡単に割り込まれます

 

注意ポイント②

スレッドの実行性能を最大化しても、リアルタイム性を保証できるわけではない

CPU を固定的に占有することで、リアルタイム性を保証できると誤解している方が多いようです。

そもそも Linux Kernel は、リアルタイムOSではありません。
そのため、リアルタイムOSと呼ばれる uITRON とは、根本的に作りが異なります

uITRON は、タイマーの割り込みにより実行するタスクを切り替えるコンテキストスイッチを行います。
Linux は、アプリが システムコールを呼び出したりして Kernel 空間に実行が戻った際、
実行待ちの全スレッドを再スケジューリングして実行するスレッドを切り替えます。

shced_setaffinity でスレッドの実行性能を最大化したとしても、OS自体がリアルタイム性を保証しません。
割り込み処理、Buffer/Cache の確保・解放、Kernel スレッド処理、ユーザ空間での処理時間など、
様々な要因でリアルタイム制が損なわれます

 

サンプルプログラム

 実行結果
tid 2467's old affinity: 0000000f
tid 2467's new affinity: 00000002

実行環境は 4 core CPU を搭載しているため、起動直後の mask は 0xF(全CPU許可)となっています。
CPU_SET の引数 cpu を変更して複数回呼び出すことで、マスクする CPU を範囲で指定可能です。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-C言語
-, , ,