github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/iextengine/wazero/README.md (about)

     1  # iextenginewasm
     2  
     3  ## Basic Usage
     4  See [Basic Usage Test](./impl_test.go)
     5  
     6  ## Design
     7  ```mermaid
     8  erDiagram
     9  ExtSrcFile }|..|| ExtensionsTinygoLib: "imports from public repo"
    10  ExtensionsTinygoLib ||..|| ReadFromState: "used to"
    11  ExtensionsTinygoLib ||..|| CreateIntents: "used to"
    12  ReadFromState ||..|| FuncsExportedByWasmEngine: "internally calls"
    13  CreateIntents ||..|| FuncsExportedByWasmEngine: "internally calls"
    14  FuncsExportedByWasmEngine ||..|| ExtensionIO: "access to"
    15  ExtensionsTinygoLib ||--|{ FuncsImportedByWasmEngine: "has"
    16  FuncsImportedByWasmEngine ||--|| WasmAbiVersion: "has"
    17  FuncsImportedByWasmEngine ||--|| WasmOnReadValue: "has"
    18  FuncsImportedByWasmEngine ||--|| MemoryInfoFuncs: "has"
    19  FuncsExportedByWasmEngine ||--|| WazeroExtensionEngine: "part of"
    20  WasmAbiVersion ||..|| WazeroExtensionEngine: "used by"
    21  WasmOnReadValue ||..|| WazeroExtensionEngine: "callback used by"
    22  MemoryInfoFuncs ||..|| WasmEngineTests: "used by"
    23  ```
    24  
    25  ### Principles: No Garbage Collection & Restore Memory
    26  [Benchmarks show](https://github.com/heeus/core/blob/fdf52bcc6384657f214a492e8afac12c2bbaeaf6/iextenginewasm/impl_benchmark_test.go#L83) that tinygo garbage collection performance is extremely slow. Instead of making garbage collection, it is more effective to restore engine memory state when the heap is over ([benchmark1](https://github.com/heeus/core/blob/fdf52bcc6384657f214a492e8afac12c2bbaeaf6/iextenginewasm/impl_benchmark_test.go#L158), [benchmark2](https://github.com/heeus/core/blob/fdf52bcc6384657f214a492e8afac12c2bbaeaf6/iextenginewasm/impl_benchmark_test.go#L198)). 
    27  We are allowed to do this since extensions are pure functions by design.
    28  
    29  Technical solution:
    30  - `ExtBuildFile` compiles TinyGo sources to WASM with garbage collection [disabled (gc=leaking)](https://tinygo.org/docs/reference/usage/important-options/)
    31  - the `exttinygo` library is developed to minimize heap allocations
    32  - after WazeroExtensionEngine is initialized, the memory backup is saved internally;
    33  - after ANY error engine automatically restores it's memory from backup
    34  
    35  Restore benchmarks
    36  ```
    37  goos: linux
    38  goarch: amd64
    39  pkg: github.com/heeus/core/iextenginewazero
    40  cpu: 12th Gen Intel(R) Core(TM) i7-12700
    41  Benchmark_Recover/2Mib-1%-20         	  491917	      2041 ns/op	       0 B/op	       0 allocs/op
    42  Benchmark_Recover/2Mib-50%-20        	   17457	     68422 ns/op	       0 B/op	       0 allocs/op
    43  Benchmark_Recover/2Mib-100%-20       	   18838	     64025 ns/op	       0 B/op	       0 allocs/op
    44  Benchmark_Recover/8Mib-100%-20       	    5707	    204310 ns/op	       7 B/op	       0 allocs/op
    45  Benchmark_Recover/100Mib-70%-20      	    6247	    192577 ns/op	      12 B/op	       0 allocs/op
    46  ```
    47  
    48  ### Memory Overflow
    49  On memory overflow Invoke returns error like:
    50  ```
    51  wasm error: unreachable
    52  wasm stack trace:
    53  	.runtime.runtimePanic(i32,i32)
    54  	.runtime.alloc(i32) i32
    55  	.arrAppend()
    56  	.arrAppend.command_export()
    57  ```
    58  
    59  ## Benchmarks
    60  ### Extensions Code
    61  ```go
    62  //export oneGetOneIntent5calls
    63  func oneGetOneIntent5calls() {
    64  	ext.GetValue(ext.KeyBuilder(ext.StorageEvent, ext.NullEntity))
    65  	mail := ext.NewValue(ext.KeyBuilder(ext.StorageSendmail, ext.NullEntity))
    66  	mail.PutString("from", "test@gmail.com")
    67  }
    68  
    69  //export oneGetNoIntents2calls
    70  func oneGetNoIntents2calls() {
    71  	ext.GetValue(ext.KeyBuilder(ext.StorageEvent, ext.NullEntity))
    72  }
    73  
    74  //export oneGetLongStr3calls
    75  func oneGetLongStr3calls() {
    76  	value := ext.GetValue(ext.KeyBuilder(StorageTest, ext.NullEntity))
    77  	value.AsString("500c")
    78  }
    79  
    80  //export doNothing
    81  func doNothing() {
    82  }
    83  
    84  //export oneKey1call
    85  func oneKey1call() {
    86  	ext.KeyBuilder(StorageTest2, ext.NullEntity)
    87  }
    88  ```
    89  ### Results
    90  ```
    91  goos: linux
    92  goarch: amd64
    93  pkg: github.com/heeus/core/iextenginewasm
    94  cpu: 12th Gen Intel(R) Core(TM) i7-12700
    95  Benchmark_Extensions_NoGc/oneGetOneIntent5calls-20         	  882313	      1292 ns/op	    2108 B/op	      25 allocs/op
    96  Benchmark_Extensions_NoGc/oneGetNoIntents2calls-20         	 1685337	       678.3 ns/op	    1248 B/op	      13 allocs/op
    97  Benchmark_Extensions_NoGc/oneGetLongStr3calls-20           	 1682310	       682.9 ns/op	    1368 B/op	      13 allocs/op
    98  Benchmark_Extensions_NoGc/oneKey1call-20                   	 4534441	       253.6 ns/op	     280 B/op	       5 allocs/op
    99  Benchmark_Extensions_NoGc/doNothing-20                     	17558064	        62.54 ns/op	       0 B/op	       0 allocs/op
   100  PASS
   101  ```
   102