どうもこんにちわ.
この記事は Seeed UG Advent Calendar 2020 の20日目の記事です.
はじめに
NervesJP というコミュニティをやっとります.
れっつじょいなす!!
昨年のAdvent Calendarでは,23日目に『ElixirでIoT#4.2:BeagleBone GreenでNerves/Elixirを動かす』という記事をお届けしました.
ところでNervesってなんやねん!??という方は,の記事に加えて,このあたりの情報をご参照ください.
- ElixirでIoT#2.1:Nervesって何者?ラズパイでLチカできんの!?
- SlideShare:ElixirでIoT!?ナウでヤングでcoolなNervesフレームワーク
- YouTube動画:ALGYAN主催!【オンライン】Elixir/Nerves入門!堅牢なIoT Edgeデバイスプログラミングをお手軽に
今年のAdvent Calendarでは,レペゼンNervesJPのAdvent Calendar芸人!?な @torifukukaiou さんより,こんな記事をお届けしております.
- 13日目:『Grove Base HAT for RasPiは真っ直ぐグイっとさす』
- 14日目:『Grove - Buzzer をNervesで鳴らす』
- 18日目:『GrovePi+ Starter Kit for Raspberry Pi A+,B,B+&2,3,4 (CE certified) 〜Nervesならできるもん!〜』
$\huge{Nervesならできるもん!}$
って言いたいだけですのやつね〜 30回くらい笑わせてもらいました^^;
ということでこの記事では,@torifukukaiou さんを見習って,日頃よりNervesJPでお世話になっておりますSeeed K.K.さんへの**感謝の恩返し!!**ということで,BeagleBone Greenで遊べるヒトネタをご紹介したいと思います.
[PR] Seeed K.K.さん,太っ腹!! [広告]
※プレゼント枠は瞬殺でした,,, でもまだ見学枠でぜひ!!
【オンライン】豪華プレゼント付!Elixir/Nerves(ナーブス)体験ハンズオン!
Nerves開発環境の準備方法
おぉっなんかNerves楽しそうだ!すぐに試してみたい!!という方向けに,VS Code dev-containerを使ったお手軽な開発環境を用意しています.ぜひどうぞです^^;
いやっガッツリNervesやっていくぜ!という方は,コチラをどうぞです.
- Mac,Linux向け:『ElixirでIoT#4.1:Nerves開発環境の準備(2020年11月版)』
- Windows(WSL 2)向け:『ElixirでIoT#4.1.1:WSL 2でNerves開発環境を整備する』
動作周波数の制御??
いわゆるDVFS(Dynamic Voltage and Frequency Scaling)というやつです.
Linuxが普通に動くような最近のSoCでは,そのプロセッサの動作周波数を何段階かに変更することができます.アプリの処理が忙しいときは高い周波数で速く動いて,ヒマなときは周波数を低くしてゆっくり動かすことができます.
なにが嬉しいかというと,消費エネルギーの節約に繋がります.
動作周波数と供給電圧は比例関係にあり,電圧を下げることによって消費電力を削減することができます.周波数を低くしたらアプリの実行時間は大きくなりますが,消費エネルギー的には小さく抑えられることが多いです(正確にはもうちょいありますが,ザックリ説明ということで^^;
Linux v3.4以降では cpufreq
というモジュールが標準で搭載されています.
Nervesでは(というかLinux)では,このモジュールを使ってプロセッサの周波数を変更することができます.
BeagleBone Green対応のNerves(本記事執筆時点の最新版 nerves_system_bbb v2.8.2
)では,組み込みLinuxであるBuildroot v2020.08.2が動作しています.Linux kernelのバージョンは5.4です.
要するに,NervesでもDVFSできるぜっ!てことです.
cpufreqの構成
cpufreq
というモジュールは /sys/devices/system/cpu/cpufreq/policy0/
にあります.Nervesの動作するBeagleBone Greenにアクセスしして,その構成を見てみましょう.
$ ssh nerves.local
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info.
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:
RingLogger.attach
or print the next messages in the log:
RingLogger.next
iex(1)> cpufreq_dir = "/sys/devices/system/cpu/cpufreq/policy0/"
"/sys/devices/system/cpu/cpufreq/policy0/"
iex(2)> ls cpufreq_dir
affected_cpus cpuinfo_cur_freq cpuinfo_max_freq
cpuinfo_min_freq cpuinfo_transition_latency related_cpus
scaling_available_frequencies scaling_available_governors scaling_cur_freq
scaling_driver scaling_governor scaling_max_freq
scaling_min_freq scaling_setspeed stats
いろんなファイルがあるので,要点な感じだけ.
- cpuinfo_cur_freq: 現在の動作周波数
- cpuinfo_max_freq, _min_freq: 設定可能な最大/最小の周波数
- scaling_available_frequencies: 設定可能な周波数の一覧
- scaling_available_governors: 設定可能なガバナの一覧
- scaling_max_freq, _min_freq: ガバナで調節される周波数の上限/下限値(設定値)
- scaling_setspeed: 手動で調節する場合の周波数の設定値
設定可能な周波数
BeagleBone Greenで設定可能な周波数の一覧を見てみましょう.
iex(3)> cat(cpufreq_dir <> "scaling_available_frequencies")
300000 600000 720000 800000 1000000
単位はKHzです.つまり300MHzから1.0GHzまでの5段階の周波数が設定できるわけです.
設定可能なガバナ
ガバナ(governor)というのは,cpufreq
で提供される標準で用意されている周波数制御のポリシーです.BeagleBone GreenのNervesではこんな感じになっています.
iex(4)> cat(cpufreq_dir <> "scaling_available_governors")
ondemand userspace powersave conservative performance
5種類のガバナがあります.ざっくりこんな感じです.
governor | 意味 |
---|---|
performance | 常に最大の動作周波数に固定 |
powersave | 常に最小の動作周波数に固定 |
userspace | ユーザの指定する周波数で動作 |
ondemand | アプリ動作負荷に応じて自動調節 |
conservative | アプリ動作負荷に応じて,適応的に自動調節 |
ondemand
と conservative
の違いは,前者はCPU使用率に応じてすぐにその対応する周波数に切り替える(例えば300MHzから一気に800MHzに変更したりする)のに対して,後者はゆっくり適応的に切り替えます(例えば300MHzから,600MHzと720MHzを経由して,それでも負荷が高ければ800MHzにする)
ちなみにデフォルト(電源リセット後)の設定は conservative
です.
iex(5)> cat(cpufreq_dir <> "scaling_governor")
conservative
設定方法
Linuxカーネルに設定を任せる場合は,scaling_governor
に設定したいガバナを書き込むだけです.
最大にする performance
と最小にする powersave
にして,周波数を見てみましょう.
iex(6)> File.write(cpufreq_dir <> "scaling_governor", "performance")
:ok
iex(7)> cat(cpufreq_dir <> "cpuinfo_cur_freq")
1000000
iex(8)> File.write(cpufreq_dir <> "scaling_governor", "powersave")
:ok
iex(9)> cat(cpufreq_dir <> "cpuinfo_cur_freq")
300000
まぁカーネルに任せといたほうが良いんですが,どうしても自分で変えたい!という場合は,ガバナを userspace
に設定して, scaling_setspeed
に設定可能な値を書き込みます.
iex(10)> File.write(cpufreq_dir <> "scaling_governor", "userspace")
:ok
iex(11)> File.write(cpufreq_dir <> "scaling_setspeed", "720000")
:ok
iex(12)> cat(cpufreq_dir <> "cpuinfo_cur_freq")
720000
効果のほどは??
それでは周波数制御の効果を見てみましょう.
こんな感じで,フィボナッチ数を求める関数をベタに実装しました.
defmodule NervesBbg do
@moduledoc """
Documentation for NervesBbg.
"""
@doc """
Calculate Fibonacci number by recursive call.
## Examples
iex> NervesBbg.fib(20)
6765
"""
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n-1) + fib(n-2)
end
周波数を下から順に切り替えて,:timer.tc
で実行時間を測定してみました.
iex(13)> File.write(cpufreq_dir <> "scaling_setspeed", "300000")
:ok
iex(14)> :timer.tc(NervesBbg, :fib, [20])
{7184, 6765}
iex(15)> File.write(cpufreq_dir <> "scaling_setspeed", "600000")
:ok
iex(16)> :timer.tc(NervesBbg, :fib, [20])
{3570, 6765}
iex(17)> File.write(cpufreq_dir <> "scaling_setspeed", "720000")
:ok
iex(18)> :timer.tc(NervesBbg, :fib, [20])
{3032, 6765}
iex(19)> File.write(cpufreq_dir <> "scaling_setspeed", "800000")
:ok
iex(20)> :timer.tc(NervesBbg, :fib, [20])
{2645, 6765}
iex(21)> File.write(cpufreq_dir <> "scaling_setspeed", "1000000")
:ok
iex(22)> :timer.tc(NervesBbg, :fib, [20])
{2127, 6765}
おぉっ,なんだか速くなっているようです.
表にするとこんな感じです.
周波数[KHz] | 実行時間[us] |
---|---|
300000 | 7184 |
600000 | 3570 |
720000 | 3032 |
800000 | 2645 |
1000000 | 2127 |
おわりに
ということでこの記事では,Nervesで動作周波数を制御する方法を紹介しました.
ていうか実はNervesどうこうじゃなく,Linuxが"いごく"んならなんでもおけです.
それといろいろ設定できますが,ガバナは割りと賢いので,デフォルトの conservative
にしとけば性能と電力のバランスは良いです.
ただし周波数が切り替わると実行時間が変動しますし,切り替え時に時間/エネルギーのオーバヘッドも掛かります.ちょっとシビアなことをしたいな??というときは,周波数の固定化など検討してもよいかもしれません.
ただし,じゃあ performance
で最大にしときゃええんちゃう??となると,SoC BBQがお楽しみになれるので注意しましょう^^
ということで改めまして, NervesJP にれっつじょいなす!!