mrubyc_arduinoのbuiltin symbolを削減
mrubyc_arduinoでコンパイルしたバイナリを眺めていたら、最後の方にいくつもの文字列が保存されていることに気が付いた。 それらはエラーメッセージやメソッド名に対応している。 メソッド名などは、内部ではsymbolとして取り扱われているが、それらを_autogen_builtin_symbol.hで取り込んでいる。 これらのbuiltin symbolをプログラムに組込むことによって、約6kほどのflash容量を消費している。 これを削減できれば、コンパイルサイズを小さくできるのでは無いかと思い付いて、試してみた。
他のクラスの多くは、c_*.cなどのファイルで定義されているが、 Symbolクラスについては、symbol.cの中で定義されている。 Symbolでは、文字列と内部で使う数値を対応させているが、 builtin symbolでは、その数値はMRBC_SYMID_*という定数として定義されており、 MRBC_SYM()というマクロで呼び出している。 その変換を行うために、symbolの文字列のデータがプログラム上に保存されている。 それ以外のSymbolでは数値はhash関数を用いて計算され、それがメモリ上に保存される。 そして、これらのSymbolは、method名を処理するために使われている。 マイコンでは、使うmethodの種類はそれほど多く無い場合がほとんどで、使うSymbolの数も少なくなり、使う可能性のあるbuiltin symbolをすべてflash上に保存するのは無駄にも思えるが、 メモリの使用量を減らすために、flash上にbuiltin symbolを保存しているようだ。
私がmruby/cで使おうとしているマイコンの多くは、メモリよりもflashが不足している。 そのため、flashの使用量を減らす工夫をいろいろとして来た。 その一つが、autogen_class.hで使わないmethodと対応する関数をコメントアウトして、これらのメソッドを消してしまう方法である。 これらのメソッドの名称もbuiltin symbolとして登録されているが、それらは消してしまって問題無いはずである。 そこで、autogen_class.hなどの中で登録されているmethodのみを_autogen_builtin_symbol.hに残すプログラムを作ってみた。
fld="/home/user/Arduino/libraries/mrubyc_arduino-main/src/"
fl=Dir.entries(fld).grep(/^_autogen_class/)
fl=fl.reject{|l|l=~/float/}
fl<<"vm.c"
sym=[]
fl.each{|fn|
d=open(fld+fn,"r"){|f|f.read}
d=d.gsub(/\/\*.*?\*\//m,"")
sym+=d.split(/\n/).grep(/MRBC_SYM\((.+?)\)/){$1}
}
sym=sym.uniq
fo="_autogen_builtin_symbol."
d=open(fo+"org","r"){|f|f.readlines}
dd=sym.map{|e| d.index{|l|l=~/\/\/\s*MRBC_SYMID_#{e}\s*=/} }+
sym.map{|e| d.index{|l|l=~/^\s*MRBC_SYMID_#{e}\s*=/} }
dd=dd.sort
out=[]
d.each_with_index{|l,i| out<<l if dd.include?(i) or not l=~/MRBC_SYMID_/ }
i=0
out=out.map{|l| (l=~/^\s*MRBC_SYMID_/) ? l.sub(/=\s*\d+/){"= #{i+=1}"}: l }
open(fo+"h","w"){|f| f.puts out}
ユーザーのフォルダを示す~が使えなかったので、ユーザー名はuserとしました。 autogen_class.hの/ */のコメントを除去してから処理するようにしていますが、マクロのifや//のコメントには対応しておりません。 Floatは除去する前提なので、Floatのmethodは取り込んでいません。 元の_autogen_builtin_symbol.hを_autogen_builtin_symbol.orgという名前に変えて、スクリプトを実行すると、新たな_autogen_builtin_symbol.hが出来ます。
これを組み込んでコンパイルしてみたら、私の場合は2kほどサイズが小さくなった。 一つのmethodあたり、ポインタと文字列で10バイトほどは小さくなるはずなので、100個のmethodを消すと、そのsymbolで少なくとも1kは減る計算と、大体一致している。 mrubyc_arduinoでコンパイルした時のサイズは64kほどなので、2kは3%程度に相当する。 flashが限られているマイコンでは、数パーセントでも重要だろう。 もしかすると、メモリの使用量は多少は増えるだろうが、builtin symbolを使わないようにすることも可能かも知れない。 しかし、そのためにはmruby/cのソースをいじる必要があり、あまりやりたく無いな。