エアガン測定

エアガンに関する色々を測定したりしなかったりしています http://www.eonet.ne.jp/~daisaku-tech/index.html

Linux Kernel 4.19のリアルタイム性能

cyclictestによるリアルタイム性能測定

rt-testsパッケージに含まれるcyclictestとhackbenchを使ってDebian 10(Linux Kernel 4.19)のリアルタイム性能を見てみました。

結論から言うと、latencyが1ms程度の精度で良いのであれば、PREEMPT RT Kernelではない、標準Kernel(Voluntary PREEMPT)でも十分と思います。2000年代のKernel 2.4の頃は、PREEMPT RT Kernelでないとリアルタイム性能はダメダメだったと思うのですが、今のKernelはあまり精度が必要のないかなり緩いソフトリアルタイムなら十分な性能です。

cyclictest/hackbenchコマンド

cyclictestは、nanosleepまたはclock_nanosleepを使用して、指定した時間sleepしたあとどれぐらいの時間ずれがあるのかを繰り返し測定するコマンドです。

使用例

$ sudo cyclictest --smp -m -l 30000
# /dev/cpu_dma_latency set to 0us
policy: other/other: loadavg: 0.12 0.08 1.00 1/245 1587

T: 0 ( 1585) P: 0 I:1000 C:   2152 Min:     27 Act:   64 Avg:   63 Max:      85
T: 1 ( 1586) P: 0 I:1500 C:   1421 Min:     32 Act:   63 Avg:   65 Max:     125

Ctrl-cで停止します。"-p 49"のようにオプションをつけると、SCHED_FIFOでプライオリティ49で動作します。このオプションなしの場合、通常のSCHED_OTHERで動作します。

使用例:SCHED_FIFOの場合

$ sudo cyclictest --smp -m -l 30000 -p 49
# /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.00 0.04 0.81 1/245 1596

T: 0 ( 1595) P:49 I:1000 C:   1676 Min:      5 Act:    6 Avg:    5 Max:      19
T: 1 ( 1596) P:49 I:1500 C:   1103 Min:      5 Act:    5 Avg:    5 Max:      43

また、hackbenchはCPUに負荷をかけるコマンドです。 使用例

$ hackbench -l 100000
Running in process mode with 10 groups using 40 file descriptors each (== 400 tasks)
Each sender will pass 100000 messages of 100 bytes
ここでCtrl-cにより停止すると、次の表示。
Signal 2 caught, longjmp'ing out!
longjmp'ed out, reaping children
sending SIGTERM to all child processes
signaling 400 worker threads to terminate
Time: 1.985

オプション"-l"で実行回数を指定します。

測定条件

次の条件でリアルタイム性能を測定しました。

  • ハードウェア:ECS Liva bat-mini:Celeron N2807 1.58GHz / RAM 2GB / eMMC 32GB
  • Debian GNU/Linux 10 (buster):Kernel 4.19
  • デスクトップが表示されている状態でsshによりログインし、コマンド実行。
  • 標準のKernelと、PREEMPT_RT Kernelで実行。
  • 何もアプリを起動していない状態と、hackbenchによりCPU負荷100%の状態でcyclictestを実行。
  • SCHED_OTHERと、SCHED_FIFO・プライオリティ49の2種類でcyclictestを実行。
  • ループ回数30000回。

標準Kernel

まずは標準Kernelの結果から。 uname -aの結果は次の通り。

$ uname -a
Linux XXX 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1+deb10u1 (2020-04-27) x86_64 GNU/Linux

標準Kernelのconfigは次の通り。

CONFIG_HIGH_RES_TIMERS=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set

標準Kernel:負荷なし:通常プロセス(SCHED_OTHER)

T: 0 ( 1795) P: 0 I:1000 C:  30000 Min:     10 Act:   55 Avg:   63 Max:    9281
T: 1 ( 1796) P: 0 I:1500 C:  19955 Min:     26 Act:   56 Avg:   72 Max:    9602

Celeron N2807は2コア2スレッドのため、Tは0と1の2つ。IはIntervalでCはCount。Min/Avg/Maxはそれぞれ最小/平均/最大のlatency(μs)で、Actはループごとのlatencyで、実行中はこの部分が更新され続けます。

latencyは平均63と72μsということですが、最大は9281と9602と9msを超えています。

標準Kernel:負荷100%:通常プロセス(SCHED_OTHER)

T: 0 ( 2454) P: 0 I:1000 C:  30000 Min:     48 Act:   67 Avg: 1525 Max:  101095
T: 1 ( 2455) P: 0 I:1500 C:  27390 Min:     56 Act: 1822 Avg: 1272 Max:   59227

CPU負荷100%では、平均1525と1272と1msを超えており、最大は101095と59227と100msを超える場合が出ています。

標準Kernel:負荷なし:リアルタイムプロセス(SCHED_FIFOプライオリティ49)

T: 0 ( 1928) P:49 I:1000 C:  30000 Min:      3 Act:    5 Avg:    5 Max:     289
T: 1 ( 1929) P:49 I:1500 C:  20010 Min:      4 Act:    5 Avg:    5 Max:     369

SCHED_FIFOにすると負荷なしの状態では平均5μs、最大でも289と369μsとなります。

標準Kernel:負荷100%:リアルタイムプロセス(SCHED_FIFOプライオリティ49)

T: 0 ( 2463) P:49 I:1000 C:  30000 Min:      6 Act:   18 Avg:   14 Max:     446
T: 1 ( 2464) P:49 I:1500 C:  19266 Min:      7 Act:   16 Avg:   14 Max:      32

SCHED_FIFOなら負荷100%でも平均14μs、最大446と32μsとなり、latency 1ms以下で良いようなシステムでは十分な性能となっています。

以上は標準Kernelの結果です。リアルタイムプロセスSCHED_FIFOにすればそこそこいい性能と思います。

PREEMPT RT Kernel

次にPREEMPT_RTパッチ適用版のKernelです。Debianの場合、PREEMPT_RTパッチ適用版Kernelがaptコマンドで次のように簡単にインストールできます。

$ sudo apt install linux-image-rt-amd64

uname -a の結果は次の通り。

$ uname -a
Linux XXX 4.19.0-8-rt-amd64 #1 SMP PREEMPT RT Debian 4.19.98-1+deb10u1 (2020-04-27) x86_64 GNU/Linux

Kernelのconfig

CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_RT_BASE=y
CONFIG_HAVE_PREEMPT_LAZY=y
CONFIG_PREEMPT_LAZY=y
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT__LL is not set
# CONFIG_PREEMPT_RTB is not set
CONFIG_PREEMPT_RT_FULL=y
CONFIG_PREEMPT_COUNT=y

PREEMPT RT Kernel:負荷なし:通常プロセス(SCHED_OTHER)

T: 0 (  837) P: 0 I:1000 C:  30000 Min:     10 Act:   64 Avg:   64 Max:    5289
T: 1 (  838) P: 0 I:1500 C:  19987 Min:     12 Act:   65 Avg:   65 Max:    7399

標準Kernelと大差ありません。

PREEMPT RT Kernel:負荷100%:通常プロセス(SCHED_OTHER)

T: 0 ( 1248) P: 0 I:1000 C:  30000 Min:     36 Act:   72 Avg: 1032 Max:  150414
T: 1 ( 1249) P: 0 I:1500 C:  26185 Min:     65 Act:   71 Avg:  656 Max:   68300

平均latencyが、標準Kernelより若干良いぐらい。

PREEMPT RT Kernel:負荷なし:リアルタイムプロセス(SCHED_FIFOプライオリティ49)

T: 0 (  843) P:49 I:1000 C:  30000 Min:      4 Act:    6 Avg:    5 Max:      75
T: 1 (  844) P:49 I:1500 C:  19997 Min:      4 Act:    6 Avg:    5 Max:      22

標準Kernelの同条件と比べると、最大latencyが75と22μsと、一桁少なくなっています。

PREEMPT RT Kernel:負荷100%:リアルタイムプロセス(SCHED_FIFOプライオリティ49)

T: 0 ( 1253) P:49 I:1000 C:  30000 Min:      7 Act:   15 Avg:   12 Max:      41
T: 1 ( 1254) P:49 I:1500 C:  16310 Min:      7 Act:   15 Avg:   12 Max:      29

標準Kernelの同条件と比べると、平均latencyが14μsに対して12μs、最大latencyが41と29μsと100μs以下になっています。

以上から、標準KernelよりもPREEMPT RT Kernelの方が、リアルタイムプロセスの最大latencyが少し良いという結果です。