tl;dr
きっかけは?
大学で受講している授業で、PREEMPT_RTを適用したlinux kernelを作成し動かしてみるという課題があり、その際にハマった点・苦労した点をまとめました。
基本的に、自分が行った操作とその考察に関してのみ記述しており、理解や解釈は読者に任せる方針となっておりますのでご了承ください。
使用したPCは以下の通り
前提 - 仮想マシンではRTOSは使えない -
OSを切り替える手間を省くために、最初は Oracle VM VirtualBox を利用していましたが、PREEMPT_RT patchを適用しても、Cyclictest でのレイテンシのMax が30000(ns)( = 30ms) を超えることさえあり、とてもとてもRTOSとして稼働しているとは言えない状況でした(リンク先のCyclictestの実行例ではMaxは30程度)。
※5.15.86-rt56-KY:rt kernelで、最後の-KYは識別のためのlocalversionなので無視してください。
これは当然といえば当然のことで、汎用OSであるWindowsの上で動いているvirtualboxには、そもそも適当なスケジューラアルゴリズムでしかCPUが割り当てられず、仮想マシン上でリアルタイムに最適化しても無駄だという結論に至りました。
dual boot先の Ubuntu 22.04 でRTOSをビルドする
RTOSとしてのkernelを利用するだけなら方法は大きく2つだと考えています。
- ダウンロードしてきた linux の kernel に、別途 patch をあててビルドする。
- linux-rt or linux-rt-lts(RT patchが既に適用されたlinux kernel) をダウンロードしてビルドする。
自分は当初、1の方法を用いて仮想マシン上でkernelをビルドしていましたが、その後2の方法を発見し、dual boot先のUbuntuでは2の方法しか試していません。
1の方法については、こちらのサイトを参考にしました。
【C言語】LinuxカーネルのPREEMPT_RTパッチでリアルタイムプログラミング
PREEMPT_RT linux などで検索すると簡単に見つけられて、日本語で読みやすく解説されており、大変参考になりました。一方で、記事の最後の方にある、Cyclictest の実行結果については、少しミスリードな部分があるようにも感じました(レイテンシがMax: 30000ほど)。
2の方法については、
https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable-rt.git こちらのサイトからkernelをダウンロードし(今回はlinux-stable-rt-5.15.86-rt56-rebase.tar.gzを利用しました)、1の方法で紹介したサイトを参考にビルドをしました。
Linuxカーネルの.configで「General setup -> Preemption Model -> Fully Preemptible Kernel (Real-Time)」を有効にするを忘れないようにしてください。
dual boot 先のUbuntuに PREEMPT_RT patch を適用した kernel をインストールし、再起動すればRTOS自体は利用可能になります(Cyclictest でも Max: 10~20を記録しました)。
しかし、NVIDIA GPUを積んでおり、外部ディスプレイに接続している場合、画面の解像度が低く固定されてしまう場合があります。その原因としては nvidia-driver と PREEMPT_RT の相性の悪さがあります。
(再起動後、問題がなかった方はこれ以下の記事を読む必要はないと思われます。)
ハマったポイント - RTOSにしたらUbuntuの解像度が低くなったのを直したい -
【結論】こちらのサイトを参考に、利用しているグラボに対応したドライバーを(.runファイル)インストールしたら治りました。
Installing NVIDIA drivers on a realtime Linux (PREEMPT-RT) · GitHub
.runファイルはこちらのサイトからダウンロードしてください
経緯や考察
RT patch 未適応の kernel で起動した際には解像度は正しく表示されていたものの、RTOSで起動した際は解像度が低く、Ubuntuの設定から変更しようとするも、変更不可能でした。
Ubuntuディスプレイ解像度の変更 | 1920x1080 - BioErrorLog Tech Blog
などのサイトを参考に解像度の変更を試みましたが、xrandr コマンドでエラーが発生しており、GPUから映像出力していることがバグ要因と当たりをつけて、nvidia-smi コマンドを実行するとエラーが発生しました。
ちなみに、GPUを搭載しているPCではマザーボードからの映像出力は無効にされていることがほとんどであり、実際に自分もディスプレイポートの接続先を変更してみましたがダメでした。
そこで、nvidia-driver をインストールするために run ファイル探して来て実行するも、「PREEMPT_RT patch が適用されている kernel には対応してません」等のエラーログにぶつかり、"preempt_rt nvidia"で検索したところ、【結論】で示した解決策に行きつくことが出来ました。
ということで、長くなりましたが自分は無事RTOSを動かせる環境を用意できたので、改めて開発を続けていきたいと思います。
ここまで読んでくださった方はありがとうございました。参考になった、面白かったという方は、記事にスターをつけてくれると嬉しいです。指摘、議論コメント等もお待ちしております。