はじめに
Linux カーネルのバージョン 6.12 から標準対応したオプション "PREEMPT_RT" の適用方法をご紹介します。
メモ: PREEMPT_RT は、バージョン 6.12 以前から存在していましたが、標準の Linux カーネルに対するパッチとして公開されていました。利用するにはカーネルに対してパッチをあてる対応が必要でした。
PREEMPT_RT オプションを適用した環境では、カーネルのプリエンプション機能が強化され、タスクの応答時間が大幅に短縮されます。主に産業機器、ロボティクス、通信機器など、厳密なタイミング制御が求められる分野で利用されており、標準のLinuxカーネルでは難しいリアルタイム性を実現します。
尚、PREEMPT_RT は Linux カーネルにリアルタイム性を持たせる強力な手段ですが、「リアルタイム=常に即時応答」ではありません。リアルタイムとは、決められた時間内に処理が完了することが保証されるという意味であり、必ずしも高速処理を意味するわけではありません。
注記: リアルタイム性はハードウェア構成やデバイスドライバー、ユーザー空間の設計にも大きく依存します。PREEMPT_RT を導入するだけでリアルタイム性能が得られると誤解しないよう注意が必要です。Linux カーネルによるプロセス・スケジューリングの揺らぎが抑えられた環境とご理解ください。
1. PREEMPT_RT の設定方法
Linux カーネル 6.12 以降であれば、defconfig もしくは menuconfig でカーネルのコンフィグレーション設定にオプション指定をするだけです。
以下は menuconfig 画面で PREEMPT_RT の説明を検索した画面です。
【図 1】 PREEMPT_RT の説明表示
ポイント: "Depends on" として EXPERT が記載されているので CONFIG_EXPERT の有効化も必要という意味になります。ARCH_SUPPORTS_RT は arm64 アーキテクチャー向けは標準で y (有効) となっているので気にする必要はありません。arm (32-bit) には標準対応していないためご注意ください。
注記: バージョン 6.12 時点では、パッチなしで PREEMPT_RT が利用できるターゲット・アーキテクチャーは ARM64、RISCV、X86 (32/64-bit) に限定された状態となっているようです。ARM (32-bit) 向けには引き続きパッチの適用が推奨となっています。
参考: PREEMPT_RT パッチの概要やリポジトリの所在情報は realtime:start [Wiki] を参照
1-1. defconfig での設定
defconfig ファイルの記述で対応の場合は、使用する defconfig の末尾に以下の記述を追加します。
CONFIG_EXPERT=y CONFIG_PREEMPT_RT=y
メモ: defconfig ファイルは、arch/arm/configs や arch/arm64/configs など、アーキテクチャー固有の configs ディレクトリー以下に格納されています。
ヒント: 追加する箇所は末尾でなくても大丈夫ですが、他のプリエンプション・モード設定(CONFIG_PREEMPT_NONE、 CONFIG_PREEMPT_VOLUNTARY、 CONFIG_PREMPT)との競合に注意してください。後の行で指定したモードが適用されます。
1-2. menuconfig での設定
menuconfig で設定の場合は、make menuconfig で表示される画面上でオプション設定を行います。
【図 1】 の "Location" に表示されるメニュー「General setup -> Preemption Model -> Fully Preemptible Kernel (Real-Time)」を選択しますが、事前に EXPERT を有効化しないとオプション項目が表示されません。
【図 2】 General setup -> Preemption Model(EXPERT 有効化前)
EXPERT オプションは「General setup -> Configure standard kernel features (expert users)」を選択した状態で y を入力すると有効になります。無効化する場合は n を入力すると無効になります。
【図 3】 EXPERT オプションの有効化
EXPERT 有効化の後に、再度 General setup -> Preemption Model を開くと PREEMPT_RT に該当するオプション項目 ”Fully Preemptible Kernel (Real-Time)” が表示されるので、このオプションを選択して Enter キーを入力してください。
【図 4】 General setup -> Preemption Model(EXPERT 有効化後)
あとは、< Save > を行ったうえで最上位のメニューまで移動して < Exit > すれば完了です。
【図 5】 最上位のメニュー画面
ヒント: menuconfig の操作方法は画面上部の説明コメントを参照してください。上下左右の矢印キーでメニューを移動して説明コメントにあるショートカットを入力する形で操作できます。
2. スケジューリング周期に関わるオプション(HZ)
PREEMPT_RT 以外にリアルタイム性を気にする場合に確認すべきオプションとして CONFIG_HZ という設定があります。CONFIG_HZ についても defconfig や menuconfig で変更が可能なので必要に応じて変更を行ってください。
defconfig で設定する場合は、以下のいずれかの設定を defconfig ファイルに追加してください。
CONFIG_HZ_100=y CONFIG_HZ_250=y CONFIG_HZ_300=y CONFIG_HZ_1000=y
menuconfig で設定する場合は、「Kernel features -> Timer frequency」にてオプション選択してください。
【図 6】 Kernel features -> Timer frequency
2-1. CONFIG_HZ とは?
CONFIG_HZ は、Linux カーネルにおけるタイマー割り込みの頻度(Hz)を設定するオプションです。これは、カーネルが1秒間に何回タイマー割り込みを発生させるかを定義しており、プロセスのスケジューリングやタイムアウト処理など、時間に依存する機能の精度に影響します。
設定値には以下があります:
【表 1】 CONFIG_HZ の設定値
|
設定値(周期) |
主な用途 |
| 100(10 msec) | サーバー用途など、低消費電力・低オーバーヘッドが求められる環境向け。 CONFIG_HZ_100=y で設定可能。 |
| 250(4 msec) | デスクトップ用途でバランスの取れた応答性を提供。 CONFIG_HZ_250=y で設定可能。 |
| 300(3.3 msec) | 一部の組込み用途や特殊なリアルタイム要件に対応。 CONFIG_HZ_300=y で設定可能。 |
| 1000(1 msec) | リアルタイム性が求められる環境や、ユーザー・インタラクションが多いシステム向け。 CONFIG_HZ_1000=y で設定可能。 |
注記: HZ の値を高くすると、タイマー割り込みの頻度が増え、CPU負荷が高くなる可能性があります。逆に低くすると、タイミング精度が下がるため、用途に応じた適切な設定が重要です。
メモ: Cyclone® V SoC や Arria® 10 SoC など arm アーキテクチャーの Linux 環境では 100Hz、Agilex™ 7/5/3 など arm64 アーキテクチャーの環境では 250Hz が標準となっています。
3. プリエンプション・モデル(補足)
PREEMPT_RT を含め、プリエンプション・モデルの各オプション項目を選択した場合の効果や概要についてまとめておきます。一般の情報を調べた内容となりますので参考として確認ください。
【表 2】 プリエンプション・モデルのまとめ
|
PREEMPT_NONE |
PREEMPT_VOLUNTARY |
PREEMPT |
PREEMPT_RT |
|
| 概要 | カーネル空間ではプリエンプションが発生しない。割り込みはカーネル処理が完了するまで待たされる。 | 自発的プリエンプションを提供する。カーネルが特定のポイントでのみプリエンプションを行う(例えば、カーネルが自発的にスケジューリングポイントに到達したときに行う)。 | フル・プリエンプションを提供する。カーネル内でもプリエンプション(割り込みによるタスク切り替え)が可能。 | 最も積極的なリアルタイム・プリエンプションを提供する。 |
| 用途 | 高スループットが求められるが、リアルタイム性が不要なシステム。 | デスクトップやサーバー環境で使用されるが、PREEMPT よりも低いプリエンプション・レベルとなる。 | デスクトップ環境や、ある程度のリアルタイム性が求められる組み込みシステム。 | 特定の組み込みシステムで、リアルタイム・ユーザースペース・タスクを割り込みハンドラーよりも優先する必要がある場合に使用される。 |
| メリット | カーネルの処理が中断されないためスループットが高くなる可能性がある。実装がシンプルでデバッグがしやすい。 | システムの安定性が向上し、オーバーヘッドが少ない。 | ユーザー空間だけでなく、カーネル空間でも割り込みが発生すると、より高優先度のタスクに切り替えられる。レイテンシーが低く応答性が高い。 | 優れたリアルタイム性能を提供。 |
| デメリット | レイテンシーが高く応答性が低い。 | システムの応答性はPREEMPT ほど高くない。 | PREEMPT_RT ほどのリアルタイム性能は得られない。 | オーバーヘッドが増加し、全体的なパフォーマンスが低下する可能性がある。 |
ヒント: 上記以外に PREEMPT_DYNAMIC というオプションも存在します。このオプションを選択した場合は、カーネル引数で起動時にプリエンプションのモード選択が可能です:
- preempt=none (PREEMPT_NONE)
- preempt=voluntary (PREEMPT_VOLUNTARY)
- preempt=full (PREEMPT)
※ Kernel 6.12 の時点では、PREEMPT_DYNAMIC のカーネル引数で PREEMPT_RT を選択することはできないようです。
まとめ
この記事では、Linux カーネルの PREEMPT_RT オプションについてご紹介しました。
記事の序盤にも記載しましたが、バージョン 6.12 時点で PREEMPT_RT に標準対応したアーキテクチャーは、ARM64、RISCV、x86(32/64-bit) に限定されています。ARM 32-bit の環境で PREEMPT_RT を使用したい場合は、以前と同様にターゲットのカーネルと同じバージョンのリアルタイム・パッチをダウンロードして適用する手順を踏んでご使用ください。
リアルタイム・パッチは、kernel.org が公開しているメインラインの Linux カーネルを対象としているため、SoC FPGA 向けのカーネルリポジトリの環境にパッチ適用する場合は注意が必要です。適用前後の差分確認を行うなど、意図しない変更が加わらないように注意してご対応ください。
最後に、PREEMPT_RT に標準対応した変更のコミット履歴のリンクを掲載しておきます。リンク先の履歴を見ると対象のアーキテクチャーが限定されていることがご理解いただけると思います。