-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support allocator inside of runtime #61
Closed
Closed
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a07d4fc
new allocator spec
yjhmelody 550eb24
must => MUST
yjhmelody 7804ead
remove old part
yjhmelody ce7fe44
improve
yjhmelody 12e46b7
fix date
yjhmelody 1df15d1
remove example
yjhmelody 09fe53f
more precise description
yjhmelody fad12d4
fmt
yjhmelody a5718f2
fix rfc link
yjhmelody File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# RFC-0061: Support allocator inside of runtime | ||
|
||
| | | | ||
| --------------- | ------------------------------------------------------------------------------------------- | | ||
| **Start Date** | 27 December 2023 | | ||
| **Description** | Supporting runtime built-in allocator makes the substrate runtime more versatile | | ||
| **Authors** | Jiahao Ye | | ||
|
||
## Summary | ||
|
||
Currently, substrate runtime use an simple allocator defined by host side. Every runtime MUST | ||
import these allocator functions for normal execution. This situation make runtime code not versatile enough. | ||
|
||
So this RFC proposes to define a new spec for allocator part to make substrate runtime more generic. | ||
|
||
## Motivation | ||
|
||
Since this RFC define a new way for allocator, we now regard the old one as `legacy` allocator. | ||
As we all know, since the allocator implementation details are defined by the substrate client, parachain/parathread cannot customize memory allocator algorithm, so the new specification allows the runtime to customize memory allocation, and then export the allocator function according to the specification for the client side to use. | ||
Another benefit is that some new host functions can be designed without allocating memory on the client, which may have potential performance improvements. Also it will help provide a unified and clean specification if substrate runtime support multi-targets(e.g. RISC-V). | ||
There is also a potential benefit. Many programming languages that support compilation to wasm may not be friendly to supporting external allocator. This is beneficial for other programming languages to enter the substrate runtime ecosystem. | ||
The last and most important benefit is that for offchain context execution, the runtime can fully support pure wasm. What this means here is that all imported host functions could not actually be called (as stub functions), then the various verification logic of the runtime can be converted into pure wasm, which provides the possibility for the substrate runtime to run block verification in other environments (such as in browsers and other non-substrate environments). | ||
|
||
## Stakeholders | ||
|
||
No attempt was made at convincing stakeholders. | ||
|
||
## Explanation | ||
|
||
### Runtime side spec | ||
|
||
This section contains a list of functions should be exported by substrate runtime. | ||
|
||
We define the spec as version 1, so the following `dummy` function `v1` MUST be exported to hint | ||
client that runtime is using version 1 spec, otherwise rollback to `legacy` allocator. | ||
The function should never be used, and its name is only for version checking. | ||
|
||
```wat | ||
(export "v1" (func $v1)) | ||
``` | ||
|
||
Choose this way is more generic than custom section since many other tools do not support custom section very well. But if an environment want to run it, it should always be possible to parse | ||
the export section. | ||
|
||
The allocator functions are: | ||
|
||
```wat | ||
(export "alloc" (func $alloc)) | ||
(export "dealloc" (func $dealloc)) | ||
(export "realloc" (func $realloc)) | ||
``` | ||
Comment on lines
+47
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need these with: #4 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's used by entrypoint call(e.g. runtime api), right? But optional for host functions |
||
|
||
Their signatures are: | ||
|
||
```wat | ||
(func $alloc (param $size i32) (result i32)) | ||
(func $dealloc (param $addr i32) (param $size i32)) | ||
(func $realloc (param $addr i32) (param $size i32) (param $new_size i32) (result i32)) | ||
``` | ||
|
||
Note: `dealloc`/`realloc` is not used in substrate side currently, but for the functional integrity. | ||
|
||
The following imports are disabled. | ||
|
||
The two kind of allocators(`leagcy` and `v1`) cannot know each other, and importing them will cause abnormal memory allocation. | ||
|
||
```wat | ||
(import "env" "ext_allocator_free_version_1" (func $ext_allocator_free_version_1 (type 0))) | ||
(import "env" "ext_allocator_malloc_version_1" (func $ext_allocator_malloc_version_1 (type 1))) | ||
``` | ||
|
||
The following export could be removed. The client side no need to know heap base. | ||
|
||
```wat | ||
(export "__heap_base" (global 2)) | ||
``` | ||
|
||
### Client side spec | ||
|
||
During instantiating time, add a version checking stage for wasm executor before any other wasm module checking. | ||
Check if parsed wasm module contains a exported `v1` function: | ||
|
||
- If not exist, we predicate it using legacy allocator, just do normal checking like before. Set legacy allocator be `Some` while set `v1` allocator be `None`. | ||
- If exist, we predicate it using `v1` allocator. And then we lookup and hold the exported `alloc` function for the total lifestyle of instance, return error if not exist. Set legacy allocator be `None` while set `v1` allocator be `Some`. | ||
- When wasm host functions or other entrypoint call(e.g. `runtime_apis`/`validate_block`) need to allocate memory, check if instance hold the `alloc`, if hold just call it otherwise call the legacy | ||
allocator. | ||
|
||
Detail-heavy explanation of the RFC, suitable for explanation to an implementer of the changeset. This should address corner cases in detail and provide justification behind decisions, and provide rationale for how the design meets the solution requirements. | ||
|
||
## Drawbacks | ||
|
||
The allocator inside of the runtime will make code size bigger, but it's not obvious. | ||
The allocator inside of the runtime maybe slow down(or speed up) the runtime, still not obvious. | ||
|
||
We could ignore these drawbacks since they are not prominent. And the execution efficiency is highly decided by runtime developer. We could not prevent a poor efficiency if developer want to do it. | ||
|
||
## Testing, Security, and Privacy | ||
|
||
Keep the legacy allocator runtime test cases, and add new feature to compile test cases for `v1` allocator spec. And then update the test asserts. | ||
|
||
Update template runtime to enable `v1` spec. Once the dev network runs well, it seems that the spec is implmented correctly. | ||
|
||
## Performance, Ergonomics, and Compatibility | ||
|
||
### Performance | ||
|
||
As the above says, not obvious impact about performance. And `polkadot-sdk` could offer the best practice allocator for all chains. | ||
Third party also could customized by theirself. So the performance could be improved over time. | ||
|
||
### Ergonomics | ||
|
||
Only for runtime developer, Just need to import a new crate and enable a new feature. Maybe it's convienient for other wasm-target language to implment. | ||
|
||
### Compatibility | ||
|
||
It's 100% compatible. Only Some runtime configs and executor configs need to be depreacted. | ||
|
||
For support new runtime spec, we MUST upgrade the client binary to support new spec of client part firstly. | ||
|
||
We SHALL add an optional primtive crate to enable the version 1 spec and disable the legacy allocator by cargo feature. | ||
For the first year, we SHALL disable the v1 by default, and enable it by default start in the next year. | ||
|
||
## Prior Art and References | ||
|
||
- [Move the allocator inside of the runtime](https://github.com/paritytech/substrate/issues/11883) | ||
- [Add new allocator design](https://github.com/paritytech/polkadot-sdk/pull/1658) | ||
|
||
## Unresolved Questions | ||
|
||
None at this time. | ||
|
||
## Future Directions and Related Material | ||
|
||
The content discussed with [RFC-0004](https://github.com/polkadot-fellows/RFCs/pull/4) is basically orthogonal, but it could still be considered together, and it is preferred that this rfc be implmentented first. | ||
|
||
This feature could make substrate runtime be easier supported by other languages and integreted into other ecosystem. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why we need to add this export when we could just detect whether
alloc
,realloc
anddealloc
are exported..There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this is a personal preference, if there is a v2 version, adding more features, then I always just check the version number to make sure that the subsequent logic is for that version number. Personally, I always hope that some specifications can be strongly bound to the version number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just like in this RFC, I named the original allocator
legac
, you can also call itv0
allocator. For other substrate implementations (smoldot or other language based substrate/polkadot), they can consider no longer supporting the old version, which is always clearerThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than listing RFC numbers in code comments, I prefer to use version numbers to indicate new features (I hate EIPs like that)