|
| 1 | +# LessVM Implementation Details |
| 2 | + |
| 3 | +This document provides details about the implementation of LessVM, focusing on recent changes and optimizations. |
| 4 | + |
| 5 | +## Table of Contents |
| 6 | + |
| 7 | +- [SIMD Vector Addition](#simd-vector-addition) |
| 8 | +- [Data Structure Store](#data-structure-store) |
| 9 | +- [Memory Management](#memory-management) |
| 10 | +- [Opcode Implementations](#opcode-implementations) |
| 11 | + - [Solana Account Operations](#solana-account-operations) |
| 12 | + - [Graph Operations](#graph-operations) |
| 13 | + - [OHLCV Operations](#ohlcv-operations) |
| 14 | + - [Hypergraph Operations](#hypergraph-operations) |
| 15 | + |
| 16 | +## SIMD Vector Addition |
| 17 | + |
| 18 | +The `vector_add` function uses SIMD (Single Instruction, Multiple Data) instructions to efficiently add multiple values at once. The implementation loads two vectors from the stack and adds them together. |
| 19 | + |
| 20 | +```mermaid |
| 21 | +sequenceDiagram |
| 22 | + participant VM |
| 23 | + VM->>VM: _mm256_loadu_si256(stack[top] to values2) |
| 24 | + VM->>VM: stack.pop() x 4 |
| 25 | + VM->>VM: _mm256_loadu_si256(stack[top] to values1) |
| 26 | + VM->>VM: result = _mm256_add_epi64(values1, values2) |
| 27 | + VM->>VM: stack.push(result) x 4 |
| 28 | +``` |
| 29 | + |
| 30 | +The function works as follows: |
| 31 | +1. Load the second vector (values2) from the top of the stack |
| 32 | +2. Pop the first 4 values from the stack |
| 33 | +3. Load the first vector (values1) from the new top of the stack |
| 34 | +4. Add the two vectors together using SIMD instructions |
| 35 | +5. Push the result back onto the stack |
| 36 | + |
| 37 | +This approach ensures that we're adding two different vectors together, rather than adding a vector to itself. |
| 38 | + |
| 39 | +## Data Structure Store |
| 40 | + |
| 41 | +The `DataStructureStore` manages various data structures used by the VM, including BTreeMaps, Tries, Graphs, OHLCV, and Hypergraphs. |
| 42 | + |
| 43 | +```mermaid |
| 44 | +classDiagram |
| 45 | + class DataStructureStore { |
| 46 | + btrees: Vec<Option<BTreeMapDS>> |
| 47 | + tries: Vec<Option<TrieDS>> |
| 48 | + graphs: Vec<Option<GraphDS>> |
| 49 | + ohlcvs: Vec<Option<OHLCVDS>> |
| 50 | + hypergraphs: Vec<Option<HypergraphDS>> |
| 51 | + +new() DataStructureStore |
| 52 | + +ensure_capacity(ds_type: DataStructureType, id: usize) void |
| 53 | + } |
| 54 | + note for DataStructureStore "Stores different types of data structures." |
| 55 | +``` |
| 56 | + |
| 57 | +The `ensure_capacity` method ensures that the vectors have enough capacity to store a data structure at a specific index. If the index is beyond the current length of the vector, the vector is resized to accommodate the new index. |
| 58 | + |
| 59 | +```mermaid |
| 60 | +sequenceDiagram |
| 61 | + participant VM |
| 62 | + participant DataStructureStore |
| 63 | + VM->>DataStructureStore: ensure_capacity(DataStructureType::BTreeMap, 5) |
| 64 | + alt Vector length < 6 |
| 65 | + DataStructureStore->>DataStructureStore: resize_with(6, || None) |
| 66 | + else Vector length >= 6 |
| 67 | + DataStructureStore->>DataStructureStore: Do nothing |
| 68 | + end |
| 69 | +``` |
| 70 | + |
| 71 | +## Memory Management |
| 72 | + |
| 73 | +The memory management system has been optimized to use a more efficient growth strategy. Instead of doubling the capacity when more space is needed, the new implementation grows the memory by 50% or to the required size, whichever is larger. |
| 74 | + |
| 75 | +```mermaid |
| 76 | +sequenceDiagram |
| 77 | + participant Memory |
| 78 | + participant Vec |
| 79 | + Memory->>Memory: ensure_capacity(required_size) |
| 80 | + alt required_size > data.len() |
| 81 | + Memory->>Memory: new_capacity = (data.len() * 3 / 2).max(required_size) |
| 82 | + Memory->>Vec: resize(new_capacity, 0) |
| 83 | + else required_size <= data.len() |
| 84 | + Memory->>Memory: Do nothing |
| 85 | + end |
| 86 | +``` |
| 87 | + |
| 88 | +This approach reduces memory waste while still providing amortized constant-time operations. |
| 89 | + |
| 90 | +## Opcode Implementations |
| 91 | + |
| 92 | +### Solana Account Operations |
| 93 | + |
| 94 | +The following Solana account operations have been implemented: |
| 95 | + |
| 96 | +- `GetBalance`: Gets the balance (lamports) of an account |
| 97 | +- `GetOwner`: Gets the owner of an account |
| 98 | +- `IsWritable`: Checks if an account is writable |
| 99 | +- `IsSigner`: Checks if an account is a signer |
| 100 | + |
| 101 | +```mermaid |
| 102 | +sequenceDiagram |
| 103 | + participant VM |
| 104 | + participant Account |
| 105 | + VM->>VM: Pop account_idx from stack |
| 106 | + VM->>VM: Check if account_idx is valid |
| 107 | + alt Valid account_idx |
| 108 | + VM->>Account: Get account information |
| 109 | + Account->>VM: Return account information |
| 110 | + VM->>VM: Push result to stack |
| 111 | + else Invalid account_idx |
| 112 | + VM->>VM: Return InvalidAccount error |
| 113 | + end |
| 114 | +``` |
| 115 | + |
| 116 | +### Graph Operations |
| 117 | + |
| 118 | +The following graph operations have been implemented: |
| 119 | + |
| 120 | +- `GraphAddEdge`: Adds an edge to a graph |
| 121 | +- `GraphGetNode`: Gets the value of a node |
| 122 | +- `GraphSetNode`: Sets the value of a node |
| 123 | +- `GraphGetNeighbors`: Gets the neighbors of a node |
| 124 | +- `GraphBfs`: Performs a breadth-first search starting from a node |
| 125 | +- `GraphClear`: Clears a graph |
| 126 | + |
| 127 | +```mermaid |
| 128 | +sequenceDiagram |
| 129 | + participant VM |
| 130 | + participant DataStructureStore |
| 131 | + participant GraphDS |
| 132 | + VM->>VM: Pop weight, to, from, and id from stack |
| 133 | + VM->>DataStructureStore: Access graph with id |
| 134 | + alt Graph exists |
| 135 | + DataStructureStore->>GraphDS: add_edge(from, to, weight) |
| 136 | + GraphDS-->>DataStructureStore: Result |
| 137 | + else Graph does not exist |
| 138 | + DataStructureStore-->>VM: Error: InvalidDataStructureOperation |
| 139 | + end |
| 140 | +``` |
| 141 | + |
| 142 | +### OHLCV Operations |
| 143 | + |
| 144 | +The following OHLCV (Open-High-Low-Close-Volume) operations have been implemented: |
| 145 | + |
| 146 | +- `OhlcvAddBar`: Adds a bar to an OHLCV |
| 147 | +- `OhlcvGetBar`: Gets a bar from an OHLCV |
| 148 | +- `OhlcvSma`: Calculates the Simple Moving Average (SMA) of an OHLCV |
| 149 | + |
| 150 | +```mermaid |
| 151 | +sequenceDiagram |
| 152 | + participant VM |
| 153 | + participant DataStructureStore |
| 154 | + participant OHLCVDS |
| 155 | + VM->>VM: Pop timestamp, open, high, low, close, volume, and id from stack |
| 156 | + VM->>DataStructureStore: Access ohlcv with id |
| 157 | + alt OHLCV exists |
| 158 | + DataStructureStore->>OHLCVDS: add_entry(timestamp, open, high, low, close, volume) |
| 159 | + OHLCVDS-->>DataStructureStore: Result |
| 160 | + else OHLCV does not exist |
| 161 | + DataStructureStore-->>VM: Error: InvalidDataStructureOperation |
| 162 | + end |
| 163 | +``` |
| 164 | + |
| 165 | +### Hypergraph Operations |
| 166 | + |
| 167 | +The following hypergraph operations have been implemented: |
| 168 | + |
| 169 | +- `HyperAddNode`: Adds a node to a hypergraph |
| 170 | +- `HyperAddEdge`: Adds an edge to a hypergraph |
| 171 | +- `HyperAddNodeToEdge`: Adds a node to an edge in a hypergraph |
| 172 | + |
| 173 | +```mermaid |
| 174 | +sequenceDiagram |
| 175 | + participant VM |
| 176 | + participant DataStructureStore |
| 177 | + participant HypergraphDS |
| 178 | + VM->>VM: Pop node_id, edge_id, and id from stack |
| 179 | + VM->>DataStructureStore: Access hypergraph with id |
| 180 | + alt Hypergraph exists |
| 181 | + DataStructureStore->>HypergraphDS: add_node_to_edge(edge_id, node_id) |
| 182 | + HypergraphDS-->>DataStructureStore: Result |
| 183 | + else Hypergraph does not exist |
| 184 | + DataStructureStore-->>VM: Error: InvalidDataStructureOperation |
| 185 | + end |
| 186 | +``` |
0 commit comments