$30 off During Our Annual Pro Sale. View Details »

(partially) Non-volatile mruby

(partially) Non-volatile mruby

presentation material of "(partially) Non-volatile mruby" in RubyKaigi 2019
https://rubykaigi.org/2019/presentations/yuri_at_earth.html

Yamanekko

April 20, 2019
Tweet

More Decks by Yamanekko

Other Decks in Programming

Transcript

  1. (partially) Non-volatile mruby
    2019-04-20 RubyKaigi 2019
    Yurie Yamane / Masayoshi Takahashiɹ
    Team Yamanekko

    View Slide

  2. Note: This is a technical session using C
    ‣You need to know about C language basics
    ‣ constant (const)
    ‣ structure
    ‣ pointers and references

    View Slide

  3. Understand this session
    Completely in 10 seconds

    View Slide

  4. What do we want to do in 10 sec.
    While Executing (current)
    ROM
    Ruby’s Objects
    RAM

    View Slide

  5. What do we want to do in 10 sec.
    Before Executing (current)
    ROM
    RAM
    Ruby’s Objects

    View Slide

  6. What do we want to do in 10 sec.
    Before Executing (ours)
    ROM
    RAM
    Ruby’s Objects

    View Slide

  7. What do we want to do in 10 sec.
    While Executing (ours)
    RAM
    new Ruby’s Objects
    ROM
    Ruby’s Objects

    View Slide

  8. Contents
    ‣ Understand this session completely in 10 seconds
    ‣ Why ROM and RubyKaigi 2018 wrap up and new our
    approach
    ‣ nvgen
    ‣ Introduction to mruby’s objects in C
    ‣ Class objects in depth
    ‣ Fix to work with ROM
    ‣ Benchmark
    ‣ Future works

    View Slide

  9. About Us

    View Slide

  10. Yurie Yamane
    ‣TOPPERS project
    ‣ET Robocon

    View Slide

  11. Masayoshi Takahashi
    ‣ Ruby no Kai
    ‣ RubyKaigi
    ‣ TechBookFest
    ‣ AozoraHack

    View Slide

  12. Masayoshi Takahashi

    View Slide

  13. Today’s Topic

    View Slide

  14. memory management
    in mruby
    for embedded systems

    View Slide

  15. RubyKaigi 2018

    View Slide

  16. https://www.slideshare.net/yamanekko/mruby-can-be-more-
    lightweight-102604291

    View Slide

  17. Why and How

    View Slide

  18. Why
    QSJDF 3". 30. NSVCZ
    -&(0
    .JOE4UPSNT
    ZFO .# .# 0,
    (31&"$) ZFO .# .# 0,
    .4UBDL ZFO ,# .# 0,
    OVDMFP';( ZFO ,# ,# 0,
    OVDMFP'3& ZFO ,# ,# 0,
    OVDMFP'3& ZFO ,# ,#
    "SEVJOPVOP ZFO ,# ,# /(
    ref)

    View Slide

  19. How
    A
    B
    C
    reduce RAM
    use ROM
    tuning by #define
    change
    implementation

    View Slide

  20. Why do we want to use ROM more
    ‣RAM is small and precious
    ‣ROM is large, but not used well in dynamic
    language
    ‣because ROM cannot be modified in
    execution time

    View Slide

  21. Every Objects
    in Flash ROM???

    View Slide

  22. hello world in mruby
    #include
    #include
    int main(void) {
    mrb_state *mrb = mrb_open();
    if (!mrb) { /* handle error */ }
    mrb_load_string(mrb, "puts 'hello world'");
    mrb_close(mrb);
    return 0;
    }
    initialize
    load & run
    app.c

    View Slide

  23. hello world in mruby
    #include
    #include
    #include “bytecode.h”
    int main(void) {
    mrb_state *mrb = mrb_open();
    if (!mrb) { /* handle error */ }
    mrb_load_irep(mrb, code);
    mrb_close(mrb);
    return 0;
    }
    initialize
    load
    & run
    const uint8_t code[] = {

    0x45,0x54,0x49,0x52,

    0x30,0x30,0x30,0x35,

    0x3b,0x7c,0x00,0x00,

    0x00,0x58,0x4d,0x41,

    0x54,0x5a,0x30,0x30,

    0x30,0x30,0x49,0x52,

    0x45,0x50,0x00,0x00,

    0x00,0x3a,0x30,0x30,

    0x30,0x32,0x00,0x00,

    0x00,0x56,0x00,0x01,

    0x00,0x04,0x00,0x00,

    0x00,0x00,0x00,0x0c,

    0x10,0x01,0x4f,0x02,
    app.c bytecode.h

    View Slide

  24. Build apps of mruby
    Ruby script

    sample.rb bytecode.h
    app.c
    executable
    mrbc
    GCC

    View Slide

  25. mrb_open()
    ‣Initialization ≒ mrb_open();

    View Slide

  26. Every Objects
    in initialized stage
    in Flash ROM?

    View Slide

  27. mrb_open()
    ‣Initialize GC and heap memory
    ‣initialize Symbols and Strings
    ‣Initialize Standard Classes in C
    ‣initialize Standard Classes in Ruby
    ‣initialize mrbgems in C and/or Ruby

    View Slide

  28. mrb_open()
    ‣Initialize GC and heap memory
    ‣initialize Symbols and Strings
    ‣Initialize Standard Classes in C
    ‣initialize Standard Classes in Ruby
    ‣initialize mrbgems in C and/or Ruby

    View Slide

  29. What’s Difference
    ‣Previous approach
    ‣Symbols and method definitions
    ‣New approach
    ‣+ Objects and IREPs

    View Slide

  30. Previous / New
    ROM
    ROM
    ROM
    RAM
    RAM
    RAM
    2018 2019
    ROM RAM

    View Slide

  31. Our approach (in Ruby)
    A = Array.new

    A << 1

    if A.size >= 1

    A += [2, 3]

    end

    A = [1, 2, 3]
    original generated

    View Slide

  32. Our approach (in Ruby)
    A = Array.new

    A << 1

    if A.size >= 1

    A += [2, 3]

    end

    A = [1, 2, 3]
    original generated
    A : [1, 2, 3]
    Internal data
    structure

    View Slide

  33. Our approach
    ‣ build generator with mruby
    ‣ executing mrb_open()
    ‣ generate C files using mruby
    ‣ build new executable (binary)
    ‣ execute
    mrb_load_state_allocf()ɹ
    in runtime
    *.c
    mruby
    mruby
    app.c
    runtime
    generator
    Executable

    View Slide

  34. mrb_load_state_allocf()
    ‣ mrb_open()
    ‣ normal VM initializer
    ‣mrb_open_allocf(mrb_allocf f, void *ud)

    ‣use custom allocation function f
    ‣ mrb_load_state_allocf(mrb_state *mrb,
    mrb_allocf f, void *ud)
    ‣ use custom allocation function and initialized VM image

    View Slide

  35. Using ROM

    View Slide

  36. How to put them on ROM
    ‣ use structures
    ‣ use const
    const char nv_string_0[] =
    "mruby - Copyright (c) …";
    const struct RString nv_object_141 = {
    .tt=MRB_TT_STRING,
    .color=7,
    .flags=141,
    .c=(struct RClass *)&nv_object_186,
    .gcnext=NULL,
    .as = {
    .heap = {
    .ptr=(char *)&nv_string_0
    }
    }
    };
    generated.c

    View Slide

  37. How to put them on ROM
    generated.c mruby
    Executable
    +

    View Slide

  38. How to put Symbols on ROM
    ‣ All Symbols should be defined
    ‣ to use structures in ROM
    ‣ Access to Symbols should be fast
    ‣ → We use gperf (perfect hash Generator)

    View Slide

  39. How to put Symbols on ROM
    ‣ generate *.key file from
    symbol objects
    ‣ generate *.c file with gperf
    presym.key
    Symbols
    presym.c

    View Slide

  40. How to put them on ROM
    generated.c mruby
    Executable
    +
    + presym.c

    View Slide

  41. nvgen

    View Slide

  42. nvgen
    ‣ Non-Volatile mruby GENerator
    ‣ generate 2 files
    ‣generated.c
    ‣presym.key

    View Slide

  43. nvgen
    ‣ execute mrb_open()
    ‣ generate Objects, strings,
    symbols as C structures
    ‣ dump all symbols into
    presym.key
    ‣ dump all structures into
    generated.c
    mruby
    nvgen
    generated.c presym.c
    presym.key

    View Slide

  44. Can we put them all on ROM?
    ‣Of course, No
    ‣Many methods to update pre-defined objects
    ‣Open classes
    ‣Object#freeze
    ‣String#reverse!

    View Slide

  45. Introduction to
    mruby’s Objects
    in C

    View Slide

  46. mruby’s Objects in C
    ‣mrb_value
    ‣small objects data represented in 4 bytes
    ‣ex) Integer, Symbol, true/false/nil
    ‣struct RBasic*
    ‣objects data larger than 4 bytes
    ‣ex) String, Array, Class, user-defined classes

    View Slide

  47. mrb_value
    ‣ Object itself
    ‣ mrb_vtype: value type
    ‣ value: i (Integer), sym
    (Symbol), p (others)
    ‣ p is pointer to RXXX
    typedef
    struct mrb_value {
    union {
    void *p;
    mrb_int i;
    mrb_sym sym;
    } value;
    enum mrb_vtype tt;
    } mrb_value;

    View Slide

  48. struct RBasic
    ‣ body of Object
    ‣ color: for GC
    ‣ flags: attrs of the object
    ‣ c: class of the object
    ‣ gcnext: for GC
    #define
    MRB_OBJECT_HEADER \
    enum mrb_vtype tt:8;\
    uint32_t color:3;\
    uint32_t flags:21;\
    struct RClass *c;\
    struct RBasic *gcnext
    struct RBasic {
    MRB_OBJECT_HEADER;
    };

    View Slide

  49. other struct RXXXX
    ‣ RObject is Object class
    ‣ RClass is Class class
    ‣ RClass have super class
    and method tables
    ‣ Similar to RArray, RHash,
    and so on
    struct RObject {
    MRB_OBJECT_HEADER;
    struct iv_tbl *iv;
    };
    struct RClass {
    MRB_OBJECT_HEADER;
    struct iv_tbl *iv;
    struct kh_mt *mt;
    struct RClass
    *super;
    };

    View Slide

  50. Class objects in depth

    View Slide

  51. mruby VM has class objects
    Proc
    String
    Float
    Fixnum
    Symbol
    Kernel
    Object
    Class
    Array
    Hash
    TrueClass
    FalseClass
    Module Range NilClass
    mrb_state
    (mruby VM)

    View Slide

  52. class has ivars and methods
    iv
    mt
    internal data
    methods
    class

    object

    (RClass)
    iv: instance variable
    mt: method table

    View Slide

  53. Ruby objects are struct in C
    struct RClass {
    MRB_OBJECT_HEADER;
    struct iv_tbl *iv;
    struct kh_mt *mt;
    struct RClass *super;
    };

    View Slide

  54. Memory Usage
    ‣Flash (ROM)
    ‣Heap (RAM)
    ‣use with malloc()
    ‣target of GC
    ‣Global variables (RAM)
    ‣use without malloc()

    View Slide

  55. Which’s in ROM, Which’s in RAM
    ‣ROM: Immutable things
    ‣RAM: Mutable things
    ‣a member of Immutable structure can be
    Mutable
    ‣and vice versa

    View Slide

  56. Which’s in ROM, Which’s in RAM
    class
    mrb_state
    iv_tbl
    internal data
    methods
    ROM
    mt
    methods
    HEAP GV

    View Slide

  57. Which’s in ROM, Which’s in RAM
    class
    mrb_state
    iv_tbl
    internal data
    methods
    GV ROM
    mt
    methods
    HEAP

    View Slide

  58. What’s structures in ROM
    ‣Objects (RBasic)
    ‣Symbols
    ‣Strings
    ‣IREPs
    ‣methods defined in initializing time
    ‣copy of VM (mrb_state)

    View Slide

  59. What’s structures in RAM
    ‣body of Hash
    ‣body of instance variables
    ‣methods defined at executing time
    ‣context
    ‣instance_vars and methods
    ‣current VM (mrb_state)

    View Slide

  60. Is it work?
    ‣You’ll get many problems
    ‣cannot define new classes
    ‣cannot use mrb_free()
    ‣cannot do GC
    ‣cannot use Object#freeze

    View Slide

  61. Is it work?
    ‣You’ll get many problems
    ‣cannot find (function|variable) names of C from
    (function|variable) addresses
    ‣need to generate C code

    View Slide

  62. Fix to work with ROM

    View Slide

  63. Function Name Resolution
    mrb_method_t vals = mrb_malloc(mrb, /* ... */);
    vals[0].func_p = 1;
    vals[0].func = gc_start;
    dump_vals(vals);
    const mrb_method_t nv_mt_vals_1[] = {
    {
    .func_p=1,
    {.func=(mrb_func_t)&gc_start}
    }, /* ... */
    };

    View Slide

  64. Function Name Resolution
    ‣use nm command to save symbol table of nvgen
    ‣nvgen parses the file and get address of functions
    ‣This method is used by TOPPERS configurator.
    $ nm nvgen > nvgen.syms
    $ ./nvgen nvgen.syms > generated.c

    View Slide

  65. String’s pointer to char*
    ‣String object has a pointer to C string (char*)
    ‣But String is not mutable
    ‣To fix this, String used in mruby/mrbgems should be
    freezed

    View Slide

  66. Using TLSF malloc
    ‣We want to know if a structure is in global variable area or in
    the heap area
    ‣Global variable should not be free()
    ‣Use TLSF malloc instead of standard malloc()
    ‣With TLSF malloc, we can know the object is in heap or not
    ‣see github.com/yamanekko/mruby-tlsf for detail

    View Slide

  67. GC supporting ROM and RAM
    ‣ mruby uses tri-color GC (Black, White, Gray)
    ‣ We use quad-color GC, add Red
    ‣ Red are never GCed; objects in ROM are Red
    ‣ At first of GC cycle, all children of Red objects are
    marked
    ‣ VM has a list of Red objects

    View Slide

  68. support flags in RAM
    ‣ obj->flags is used as status of objects
    ‣ flags should be mutable
    ‣ So an array of flags for ROM’s objects are
    located in RAM
    ‣ add macro to read and write them
    ‣ obj->flags in ROM are indexes of the array

    View Slide

  69. Finding methods
    ‣ method tables are in both ROM and RAM
    ‣ tables for pre-defined methods are in ROM
    ‣ using iv_tbl to store pointer of pre-defined
    method tables
    ‣ key is __mt2__, which is not used as instance
    variables

    View Slide

  70. Benchmark

    View Slide






  71. EFGBVMU /7




    View Slide

  72. Future works

    View Slide

  73. Future works
    ‣nvgen as mrbgem
    ‣feedback to mruby/mruby
    ‣workshop

    View Slide

  74. Special Thanks to:
    ‣ This work is supported Ruby Association
    grant program in 2018

    View Slide

  75. and Thank you!

    View Slide