UIAPduinoでコードゴルフ


最近,Arduinoからch32funを介してUIAPduinoを使える環境を構築している. その環境でi2cとUSB serialを使ったプログラムを作ったら,flashにギリギリのサイズになってしまった. いろいろ調べていたら,ch32funのdebug printが有効になっていたので,それをオフにしたら多少は余裕ができた. もう少しバイナリのサイズを小さく出来無いかと思って,少しいじってみた.

現時点では,ArduinoCoreAPIは組込むと決めているので,その縛りの下でArduinoが組み込んでいるC言語やC++のソースをコンパイルした後のバイナリを小さくするようにするコードゴルフのようなものかな. しかし,コンパイラがある程度の最適化を行っているので,単純では無い. 例えるならば,日本語を通訳に流暢な英語にしてもらっているときに,その英語を短かくするように,日本語を作るようなものかな.

繰り返し行われている操作を,関数にして使うようにしたら,四回ぐらいしか使わない場合には,サイズが大きくなってしまうが,それより多く使うと,小さくなった. 小技を使って4バイトずつ縮めたり,USB serialの方もいじったりして,100バイト程度は短くなった. RingBufferを使うようにしたら,ソースコードは短かくなったが,バイナリは若干大きくなってしまったので,元に戻した. ついでにi2cをslaveに対応させようとして少し書き足したら,100バイトぐらい増えてしまって,元と同じぐらいに戻ってしまった. 使ってない関数は,最適化されたら関係無いと思ったけど,なんでだろう.

折角なので, UPAIduino環境で,最適化が-Osと-Os LTOのとき, 私の構築している環境で,with USB serialとwithout USBのとき, AlexanderManderaさんの環境の, 5つの場合について,コンパイルしたときに生成されるbinファイルのサイズを比較してみた. プログラムはプログラムの例から,いろいろな機能を使う場合を選んでみた. 結果は以下の通りである. overとついているのは,flashのサイズを超えた容量を示している. Xは実装されていないことを表している.

condition Blink AnalogInput DigitalReadSerial AnalogInOutSerial i2c_scanner adafruit_aht10_test
UIAPduino -Os 7140 8656 7616 12648 13032 11024 over
UIAPduino -Os LTO 5696 6248 5872 8276 11040 error
my own with USB serial 4460 4644 4440 4844 5752 1232 over
my own without USB 3968 4168 3992 4338 5308 772 over
AlexanderMandera 1640 1932 2132 X X X

この表を見て気がついたのが,UIAPduinoでは,-Osがデフォルトになっているが,-Os LTOの方がサイズが小さくなって良さそうだということだ. UIAPduinoを使う場合には,-Os LTOで使うと良いだろう. バイナリのサイズという点では,AlexanderManderaさんの環境がかなり小さい. 私の環境は,Blinkはそれなりに大きなサイズになっているが,機能を増やしても,あまりサイズが変わらないという特徴を持っているようだ. 私の環境には最新のch32funを使っているのだが,その特徴なのかも知れない. ちなみに,シームレススイッチを組み込んでいるので,それが76バイトぐらいは大きくなっている原因だという点を考慮して欲しい. i2c_scannerはWireを使っていると言っても,ほぼ何も通信しないプログラムなので,UIAPduinoできちんとしたWireをArduinoから使えるのは,今のところ私の環境だけかも知れない. まだ,slaveが使えないが. また,adafruit_aht10_testを動かせるようにするには,かなり小さくしないといけないので,ちょっと厳しい気がする.

今後は,WireよりもBlinkのサイズが小さくなるように考えてみようかな. ch32funとArduinoでのピンの番号の取り扱い方が異なるので,その変換部分に100バイトぐらいは使っている気がするので,それを最適化できれば,少しは小さくなる気がする. でもあまり最適化すると,汎用性が無くなってしまうので,難しいところである.

[2026/3/23追記] 週末にいろいろといじって,サイズが激減したので,比較のために,それも下に表として示しておく. 結局,リンクの段階で使っていない関数も取り込んでしまっていたのが,サイズが大きくなっていた原因だったようだ. USB serialを組み込むと,その機能を使っていなくても,USBの制御部分があるので,その分サイズが大きくなってしまうようだ. ざっとチェックした感じだと,以前から動いていた機能はほぼ動くようなので,少しずつバグ取りをして行く予定だ.

condition Blink AnalogInput DigitalReadSerial AnalogInOutSerial i2c_scanner adafruit_aht10_test
with USB serial 3120 3416 3412 3824 4896 4668
without USB 768 1072 1672 2104 3192 2960