「Ubuntuでリアルタイムカーネル(PREEMPT_RT)を動かす」
ひと昔前なら、この一言だけで「あ、今日は一日中カーネルのビルドで終わるな……」と覚悟が必要な作業でした。ソースを拾ってきて、パッチを当てて、.configと格闘して、コンパイル中にエラーが出て頭を抱える。そんな時代がありました。
でも、時代は変わったんですね。 今のUbuntu(今回は24.04)なら、コマンド数回叩くだけで、あっさり公式のリアルタイムカーネルが手に入ります。
導入はいたってシンプル
Ubuntu Proを使わなくても、標準的なリポジトリ(24.04以降ならnoble-updatesなど)からパッケージとして提供されていました。
かなり昔に購入したmacminiをUbuntu化して放置していたので、それをリアルタイムカーネル化してみました。
手順は↓これだけ。
sudo apt update
sudo apt install linux-realtime
sudo apt install linux-realtime
インストール後、再起動。
かなり昔に購入したmacminiをUbuntu化した結果
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
$ uname -a
Linux macmini 6.8.1-1015-realtime #16-Ubuntu SMP PREEMPT_RT Wed Jan 15 21:03:54 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
$ uname -a
Linux macmini 6.8.1-1015-realtime #16-Ubuntu SMP PREEMPT_RT Wed Jan 15 21:03:54 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
リアルタイムカーネルの動作確認するためのサンプルコードとコンパイル
// rt_test.c
#include <stdio.h>
#include <time.h>
#include <sched.h>
int main() {
struct sched_param param = {.sched_priority = 50};
sched_setscheduler(0, SCHED_FIFO, ¶m);
struct timespec next;
clock_gettime(CLOCK_MONOTONIC, &next);
printf("時刻 周期からの誤差(μs)\n");
printf("----------------------------------\n");
while (1) {
next.tv_sec += 1;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long jitter = (now.tv_nsec - next.tv_nsec) / 1000;
time_t t = time(NULL);
struct tm *l = localtime(&t);
printf("%02d:%02d:%02d %+ld μs\n",
l->tm_hour, l->tm_min, l->tm_sec, jitter);
}
return 0;
}
#include <stdio.h>
#include <time.h>
#include <sched.h>
int main() {
struct sched_param param = {.sched_priority = 50};
sched_setscheduler(0, SCHED_FIFO, ¶m);
struct timespec next;
clock_gettime(CLOCK_MONOTONIC, &next);
printf("時刻 周期からの誤差(μs)\n");
printf("----------------------------------\n");
while (1) {
next.tv_sec += 1;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long jitter = (now.tv_nsec - next.tv_nsec) / 1000;
time_t t = time(NULL);
struct tm *l = localtime(&t);
printf("%02d:%02d:%02d %+ld μs\n",
l->tm_hour, l->tm_min, l->tm_sec, jitter);
}
return 0;
}
$ cc rt_test.c -o rt_test
リアルタイムカーネルでの実行結果
$ sudo ./rt_test
時刻 周期からの誤差(μs)
----------------------------------
21:07:28 +69 μs
21:07:29 +70 μs
21:07:30 +73 μs
21:07:31 +68 μs
21:07:32 +70 μs
21:07:33 +70 μs
21:07:34 +49 μs
21:07:35 +70 μs
21:07:36 +73 μs
21:07:37 +72 μs
時刻 周期からの誤差(μs)
----------------------------------
21:07:28 +69 μs
21:07:29 +70 μs
21:07:30 +73 μs
21:07:31 +68 μs
21:07:32 +70 μs
21:07:33 +70 μs
21:07:34 +49 μs
21:07:35 +70 μs
21:07:36 +73 μs
21:07:37 +72 μs
普通のカーネルでの実行結果
$ sudo ./rt_test
時刻 周期からの誤差(μs)
----------------------------------
21:07:28 +285 μs
21:07:29 +296 μs
21:07:30 +291 μs
21:07:31 +217 μs
21:07:32 +301 μs
21:07:33 +237 μs
21:07:34 +200 μs
21:07:35 +336 μs
21:07:36 +298 μs
21:07:37 +248 μs
時刻 周期からの誤差(μs)
----------------------------------
21:07:28 +285 μs
21:07:29 +296 μs
21:07:30 +291 μs
21:07:31 +217 μs
21:07:32 +301 μs
21:07:33 +237 μs
21:07:34 +200 μs
21:07:35 +336 μs
21:07:36 +298 μs
21:07:37 +248 μs