MicroPython的午睡(115) ESP32版、mpy-crossの利用

Joseph Halfmoon

前回はヒープ・メモリの使用状況をちょいと観察しました。上限が小さいRAM領域は貴重。ターゲット機のESP32DevKitCの場合、まだFlash領域の方が余裕があるのでなるべくFlashに「追い出したい」デス。そこで今回はMicroPythonの中間コードにクロスコンパイルしてくれるmpy-crossを使用してみます。

※「MicroPython的午睡」投稿順 Indexはこちら

mpy-cross

mpy-crossは、MicroPythonの処理系そのものをビルドするときに必須なツールです。MicroPythonのソースコードを読み取って中間コードにコンパイルしてくれるもの。MicroPython処理系のビルド時には、デフォルトで処理系に含まれている各種のMicroPythonモジュールをこのmpy-crossツールでコンパイルし、処理系のバイナリとあわせてオブジェクトファイルとしているみたいです。いつもお世話になっておりますMicroPython日本語版のドキュメントが以下に。

MicroPython .mpy ファイル

そんなツールなので、MicroPythonの処理系をビルドするためにレポジトリを git clone してあれば、mpy-crossはかならずその配下に潜んでます。

今回手元の環境にもMicroPythonのソースツリーがあったので、その横にあったmpy-crossを使ってみることにいたしました。ただし懸念点が一つ。

    • 本シリーズでもSTM32版などはソースツリーから自前でビルドしている(つまりビルドされたMicroPython処理系とmpy-crossのバージョンは適合している筈)
    • 今回使用のESP32版のMicroPython処理系は、どこぞにあったバイナリをダウンロードして書き込んで使用(多分mpy-crossのバージョンは不適合)

ということです。結論から言うと以下のようでした。

    1. mpy-crossのバージョンは不適合でも、MicroPython中間コード(機種依存なし)にクロスコンパイルしたオブジェクトはマイコン上のMicroPythonでimportして使用できた。
    2. 高速化のための@viperと呼ぶ別な形式のコード(機種依存あり)にクロスコンパイルしたオブジェクトはmpyのバージョン不適合でエラーとなった。

ということは、@viper使いたくばEPS32版もちゃんと自前でビルドしろってことかい?

mpyファイル化手順とその実行

デフォルトでmpyファイルには、機種依存でないMicroPythonの中間コードにプラスしてPythonのソース(余分な空白などは除かれている)も格納されているみたいです。生成されたmpyファイルをマイコン側のストレージ(モジュール検索パスの通っている)においておけば、import して使用することができます。

今回は、前回使用のソースをほぼほぼそのまま mpy化してみることにいたしました。前回ソースのmain関数をtest()という名に改めた mpytst.py が以下に。

import micropython, gc

xyz = micropython.const([123, 456, 789, 111, 222, 333, 444, 555, 666, 777])

def test():
    testSTR = "ESP32, memory usage."
    print(testSTR)
    gc.collect()
    print("mem_alloc:", gc.mem_alloc())
    print("mem_free:", gc.mem_free())
    print("mem_info:")
    print(micropython.mem_info())
    abc = [123, 456, 789, 111, 222, 333, 444, 555, 666, 777]
    print("mem_info(abc):")
    print(micropython.mem_info())
    del abc
    gc.collect()
    print("mem_info(del abc):")
    print(micropython.mem_info())
    del globals()['xyz']
    gc.collect()
    print("mem_info(del global xyz):")
    print(micropython.mem_info())
    
    print("qstr_info:")
    print(micropython.qstr_info())

上記のソースを以下のようにして中間コードに落とします(mpy-crossにパスが通っている場合。)

$ mpy-cross mpytst.py

上記の場合、mpytst.mpy というファイルが生成されます。これが中間コードのファイルです。このファイルをマイコン側のストレージに転送しておきます。Thonny利用の場合は、Filesタブで該当のmpyファイルが存在するディレクトリを開いておいて、該当mpyファイルを右クリックから “upload to /” すればマイコン側ストレージのルートに転送可能です。マイコン側ストレージのルートディレクトリはデフォルトでモジュールパスに入っているようなので、ここに置いておけば、即import可能です。

実際に上記モジュールを実行するmainは以下のようにしました。

import mpytst
 
if __name__ == "__main__":
    mpytst.test()
mpy化したプログラムの実行結果

上記の実行結果の出力を前回の結果と比べてみたものが以下です。importMpytstMark

前回とほぼほぼ同じ機能ですが、16バイト減(ヒープ上1ブロック減)という結果(黄色のマーカ部)を得ました。効果はありだけれども素のままでは微妙。

一方、前回まったくRAMの削減効果がなかった大域変数の削除後、80バイト減(緑のマーカ部)を観察しました。元の値がFlashに載っている分、開放できるRAMが出来たってこと?知らんけど。

@viper使うにはバージョン合わせないと

mpy-crossには、機種非依存のMicroPython中間コードに落とすだけでなく、機種依存性のある@native、@viperという一部マシンコード的なコードに落とすオプションも使えます。調べてみると@nativeより@viperの方が速いみたいデス。なんだかよく分からんですが。

今回は@viperの方を試みましたが、先に述べたようにエラーで跳ね返されました。こんな感じ。ViperRuntimeError

mpyファイルが不適合じゃ、と。

調べてみると 今回のmpy-crossは、mpy v6.1 を吐き出すクロスツールみたいです。mpyCrossVersion

一方、ターゲット機に書き込み済のMicroPython処理系は以下です。MicroPythonVersion

この処理系がサポートしているmpy のバージョンは以下のように v6.0らしいです。ESP32supportedMPY

微妙だけど「違う」みたい。viper動かすためには処理系から更新なのでまた今度だね。。。暑いのにメンドイっす。

icroPython的午睡(114) ESP32版、ヒープ・メモリの使用状況 へ戻る

MicroPython的午睡(116) ESP32版、mip動かんぜよ? へ進む