-
Notifications
You must be signed in to change notification settings - Fork 26
Proposal for the Grant Program 2020 of Ruby Association
- Monstar Lab, inc.
- Hasumi Hitoshi
- A programmer of Monstar Lab
- A contributor to https://github.com/mrubyc/mrubyc
- Appeared in RubyKaigi Takeout 2020, 2019 and 2018, RubyConf 2019, RubyWorld Conference 2018
- The first prize winner of Fukuoka Ruby Award 2020
- mini mruby compiler (mmrbc)
mmrbc(mini mruby compiler)はRubyスクリプトをmrubyのVMコードへコンパイルする。256 KiB ROM, 128 KiB RAM程度のワンチップマイコンを動作環境として想定している。これは、mruby標準添付のmruby-compilerでは動作できない小さなリソースである。 小リソース環境向けのmruby VM実装であるmruby/cとmmrbcを組み合わせることにより、ワンチップマイコン上でRubyをインタプリタ実行できるようになる。
このシステムの用途は、コンパイルツールチェインなしで開発できるIoTデバイス入門キット、本格的な組み込みアプリケーション開発時の実機デバッグのサポート、Smalrubyと統合した学校教育向けセットアップなどが考えられる。
mmrbc (mini mruby compiler) compiles Ruby scripts into VM code of mruby. Typical operating environment is a one-chip microcontroller with 256 KiB ROM and 128 KiB RAM. It’s too small to run mruby-compiler that comes as a standard library with mruby. By combining mmrbc and mruby/c which is another mruby VM implementation for small resource environments, Ruby can run as an interpreter on a one-chip microcontroller.
Possible uses for this system include an IoT device introductory kit that can be developed without a compilation tool chain, facilitating debugging of the actual device when developing a full-scale embedded application, and a setup for school education integrated with Smalruby.
- mmrbc is a small mruby compiler which runs on a one-chip microcontroller
- Reference board of mmrbc is PSoC5LP, specifications are as follows:
- Arm 32bit architecture
- 256 KiB ROM
- 64 KiB RAM
- It is also a reference board of mruby/c
- mruby/c is a small VM implementation of mruby dedicated to one-chip microcontroller
- It assumes that VM code is compiled by Matsumoto Yukihiro-san(Matz)'s original mruby compiler (mrbc)
- It would be nice if one could execute Ruby scripts on a running microcontroller without pre-compiling
- Imagine developing an IoT project with mruby/c:
- 🎲 Changing a parameter of an analogue sensor on the fly would be very useful to find the proper configuration
- 👀 Looking at values of @ivar and $gvar could make debugging easier
- 📶 Sending arbitrary strings to a communication module could be helpful to check reachability
- However, flashing both mrbc and mruby/c onto 256 KiB ROM is difficult to realize
- Imagine developing an IoT project with mruby/c:
- This is the motivation of making a mini mruby compiler
- Portable and less dependent
- mmrbc doesn't depend on mruby nor mruby/c
- It can be built with only standard C library (libc)
- libc can be not only glibc but also Newlib and Newlib-nano
- Small footprint (by linking to Newlib-nano)
- Fits in less than 256 KiB ROM (including mruby/c VM and some app code)
- Runs on less than 64 KiB RAM
- Selectable malloc and free
- mmrbc is essentially independent from mruby/c though,
malloc
andfree
can be replaced withmrbc_alloc
andmrbc_free
which are implemented in mruby/c VM so that mmrbc can be integrated into mruby/c- (I call the integration "mmruby")
- mmrbc is essentially independent from mruby/c though,
- LEMON as a parser generator
- It is originally a parser generator of SQLite
- Nowadays, YACC/BISON is a typical choice of parser generator. Using LEMON might be unique in terms of implementing the Ruby language
In this section, both mrbc and mmrbc are built for 64-bit architecture with glibc and they use Linux file system so that we can simply compare them by using valgrind.
- mmrbc also uses glibc's
malloc
andfree
instead ofmrbc_alloc
andmrbc_free
- The branch of mruby is
mruby3
as of August 14th, 2020 - Analysis command looks like:
valgrind --tool=massif --stacks=yes path/to/(mrbc|mmrbc) source.rb
- The results shown below are larger than the results on 32-bit architecture because the size of the pointer is twice as large in 64-bit architecture
Source code: hello.rb
puts "Hello World!"
Output:
Hello World!
--------------------------------------------------------------------------------
Command: ../mruby/build/host/bin/mrbc ./hello.rb
Massif arguments: --stacks=yes
ms_print arguments: massif.out.4087
--------------------------------------------------------------------------------
KB
157.8^ #
| #
| #
| #
| #
| @#
| @#
| @#
| @@@#
| @@:::::::::::@:::::::@ @#
| @:::::::@ :::: :: :: @: :: ::@ @#
| :::::@:::::@: :: ::@ :::: :: :: @: :: ::@ @#
| ::::::::::::::::::::::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| ::::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
| : ::: ::: ::: ::: : : ::: : @:: ::@: :: ::@ :::: :: :: @: :: ::@ @#
0 +----------------------------------------------------------------------->Mi
0 3.235
--------------------------------------------------------------------------------
Command: ../mmruby/build/host-production/bin/mmrbc hello.rb
Massif arguments: --stacks=yes
ms_print arguments: massif.out.1652
--------------------------------------------------------------------------------
KB
11.17^ #
| @#
| @@# ::
| @@#:::::
| @ @ :@: : :: @@#:::::
| @ :::@: :@::: :::@@#:::::
| @ :::@: :@:::@:::@@#:::::
| @:::::@:::@:::@:::@@#:::::
| @: :::@:::@:::@:::@@#:::::
| :: @: :::@:::@:::@:::@@#::::::
| :: @: :::@:::@:::@:::@@#::::::
| :: : @: :::@:::@:::@:::@@#::::::
| :: : @: :::@:::@:::@:::@@#::::::
| :::: @: :::@:::@:::@:::@@#::::::
| :::: @: :::@:::@:::@:::@@#::::::
| :::: @: :::@:::@:::@:::@@#::::::
| :::: @: :::@:::@:::@:::@@#::::::
| :::: @: :::@:::@:::@:::@@#::::::
| :::: ::::::::::::::: @:::::@::: @: :::@:::@:::@:::@@#::::::
| ::::::::::::: :: : :::::::::@:::::@::: @: :::@:::@:::@:::@@#:::::@
0 +----------------------------------------------------------------------->ki
0 224.5
Source: larger_script.rb
ary = Array.new(3)
ary[0] = {a: 123e2}
ary[0][:key] = "string"
ary[1] = %w(abc ABC Hello)
ary[2] = 0x1f
ary[3] = !true
puts "my name is #{self.class}, result is #{ary[2] * ary[0][:a]}"
p ary
Output:
my name is Object, result is 381300
[{:a=>12300, :key=>"string"}, ["abc", "ABC", "Hello"], 31, false]
(This example also demonstrates what syntax mmrbc can already compile)
--------------------------------------------------------------------------------
Command: ../mruby/build/host/bin/mrbc ./larger_script.rb
Massif arguments: --stacks=yes
ms_print arguments: massif.out.4133
--------------------------------------------------------------------------------
KB
162.9^ ##
| #
| @#
| @#
| @#
| @#
| @:@#
| @:@#
| @:@# :
| :::@@::::::@@@@:@# :
| :::::::@::::::::::@ :: :::@ @:@# :
| ::::@@:::::@ :: ::@:: ::: :::@ :: :::@ @:@# :
| ::::::::::::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| ::::::::::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
| :: :::: ::::: :: :: ::: :@ :::: @ :: ::@:: ::: :::@ :: :::@ @:@# :
0 +----------------------------------------------------------------------->Mi
0 3.470
--------------------------------------------------------------------------------
Command: ../mmruby/build/host-production/bin/mmrbc larger_script.rb
Massif arguments: --stacks=yes
ms_print arguments: massif.out.13414
--------------------------------------------------------------------------------
KB
53.20^ #
| #
| @# :::
| @# : :
| @# : :
| @@# : :
| @@# :: :
| @@#::: :
| @@#::: :
| @@::@@#::: :
| @@: @@#::: :
| @@:@:::@::::@@: @@#::: ::
| @::@::@ :@:: @:: :@@: @@#::: ::
| @:::@@@:@::@: @ :@:: @:: :@@: @@#::: ::
| @@:@::@:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
| ::@@@ :@: @:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
| :::::: :::::@ @ :@: @:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
| :::::@@:: :::::: ::@ @ :@: @:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
| : :: @ :: :::::: ::@ @ :@: @:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
| : :: @ :: :::::: ::@ @ :@: @:: @@ :@::@: @ :@:: @:: :@@: @@#::: ::
0 +----------------------------------------------------------------------->Mi
0 1.616
Ruby script | mrbc | mmrbc |
---|---|---|
hello.rb | 157.8 KiB | 11.17 KiB |
larger_script.rb | 162.9 KiB | 53.20 KiB |
- mrbc:
- It seems to be difficult to run on 64 KiB RAM even if the platform is a 32bit architecture
- mmrbc:
- It has a good chance to run on 64 KiB RAM if Ruby script is not big
- The number of "instructions executed" tends to increase significantly as Ruby script grows
- Because some internal structure like AST may not be optimal, I guess I can improve it
- Syntax coverage is shown in these checkboxes: https://github.com/hasumikin/mmruby/pull/6
- ROM consumption is about 50% of 256 KiB
- https://github.com/hasumikin/mruby_machine_PSoC5LP
- includes: mmrbc + mruby/c + shell + peripheral drivers (UART, LED)
- Checking all unchecked checkboxes on https://github.com/hasumikin/mmruby/pull/6
- Includes:
- Conditional syntax represents
OP_JMP
OP_JMPIF
, etc. - Nested IREPs generated by
class MyClass; end
def my_method(arg); end
lambda and Proc, etc.
- Conditional syntax represents
- Includes:
- Trying to find a better internal structure to reduce RAM consumption
- The complete syntax of mruby, such as:
- The syntax which mruby/c VM doesn't cover, such as:
- module
- Multiple assignments, etc.
- The syntax which seems to be unnecessary for one-chip microcontroller
- Here document, etc.
- Furthermore, some incompatibilities are acceptable as to keep mmrbc small enough
- The syntax which mruby/c VM doesn't cover, such as:
- VM code optimization
- eg)
a = 4
can be compiled intoOP_LOAD_4 R1(a)
- instead, mmrbc always verbosely compiles into
OP_LOAD_4 R2; OP_MOVE R1(a) R2
- instead, mmrbc always verbosely compiles into
- eg)
Above features will possibly be implemented as selectable options by compile flags in the future.
- Source code of mmruby (integration of mmrbc and mruby/c): https://github.com/hasumikin/mmruby
- mrbc - Original mruby compiler written by Matz
- mmrbc - Mini mruby compiler which I am writing and what I want to be accepted for the Grant Program 2020
- mmruby - A language processing system integrating mmrbc and mruby/c
- mruby machine - Integration of mmrbc, mruby/c, shell and peripheral drivers runs on one-chip microcontroller
- I adopted the MIT License for this project, but it might have to be changed into BSD-3-Clause License due to mruby/c's current license
Copyright © HASUMI Hitoshi.