reorganize module
This commit is contained in:
7
_archive/rhai_engine/rhaibook/start/builds/index.md
Normal file
7
_archive/rhai_engine/rhaibook/start/builds/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Special Builds
|
||||
==============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
It is possible to mix-and-match various [features] of the Rhai crate to make specialized builds with
|
||||
specific characteristics and behaviors.
|
67
_archive/rhai_engine/rhaibook/start/builds/minimal.md
Normal file
67
_archive/rhai_engine/rhaibook/start/builds/minimal.md
Normal file
@@ -0,0 +1,67 @@
|
||||
Minimal Build
|
||||
=============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
In order to compile a _minimal_ build – i.e. a build optimized for size – perhaps for
|
||||
`no-std` embedded targets or for compiling to [WASM], it is essential that the correct linker flags
|
||||
are used in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[profile.release]
|
||||
lto = "fat" # turn on Link-Time Optimizations
|
||||
codegen-units = 1 # trade compile time with maximum optimization
|
||||
opt-level = "z" # optimize for size
|
||||
```
|
||||
|
||||
|
||||
Use `i32` Only
|
||||
--------------
|
||||
|
||||
For embedded systems that must optimize for code size, the architecture is commonly 32-bit.
|
||||
Use [`only_i32`] to prune away large sections of code implementing functions for other numeric types
|
||||
(including `i64`).
|
||||
|
||||
If, for some reason, 64-bit long integers must be supported, use [`only_i64`] instead of [`only_i32`].
|
||||
|
||||
|
||||
Opt-Out of Features
|
||||
-------------------
|
||||
|
||||
Opt out of as many features as possible, if they are not needed, to reduce code size because,
|
||||
remember, by default all code is compiled into the final binary since what a script requires cannot
|
||||
be predicted. If a language feature will never be needed, omitting it is a prudent strategy to
|
||||
optimize the build for size.
|
||||
|
||||
Removing the script [optimizer][script optimization] ([`no_optimize`]) yields a sizable code saving,
|
||||
at the expense of a less efficient script.
|
||||
|
||||
Omitting [arrays] ([`no_index`]) yields the most code-size savings, followed by floating-point support
|
||||
([`no_float`]), safety checks ([`unchecked`]) and finally [object maps] and [custom types] ([`no_object`]).
|
||||
|
||||
Where the usage scenario does not call for loading externally-defined modules, use [`no_module`] to
|
||||
save some bytes. Disable script-defined functions ([`no_function`]) and possibly closures
|
||||
([`no_closure`]) when the features are not needed. Both of these have some code size savings but not much.
|
||||
|
||||
For embedded scripts that are not expected to cause errors, the [`no_position`] feature can be used
|
||||
to disable position tracking during parsing. No line number/character position information is kept
|
||||
for error reporting purposes. This may result in a slightly smaller build due to elimination of code
|
||||
related to position tracking.
|
||||
|
||||
|
||||
Use a Raw [`Engine`]
|
||||
--------------------
|
||||
|
||||
[`Engine::new_raw`][raw `Engine`] creates a _raw_ engine. A _raw_ engine supports, out of the box,
|
||||
only a very [restricted set][built-in operators] of basic arithmetic and logical operators.
|
||||
|
||||
Selectively include other necessary functionalities by picking specific [packages] to minimize the footprint.
|
||||
|
||||
Packages are shared (even across threads via the [`sync`] feature), so they only have to be created once.
|
||||
|
||||
In addition, a [`Engine::new_raw`][raw `Engine`] disables the _[strings interner]_, which might
|
||||
actually increase memory usage if many strings are created in scripts. Therefore, selectively turn
|
||||
on the [strings interner] via [`Engine::set_max_strings_interned`][options].
|
80
_archive/rhai_engine/rhaibook/start/builds/no-std.md
Normal file
80
_archive/rhai_engine/rhaibook/start/builds/no-std.md
Normal file
@@ -0,0 +1,80 @@
|
||||
`no-std` Build
|
||||
==============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
The feature [`no_std`] automatically converts the scripting engine into a `no-std` build.
|
||||
|
||||
Usually, a `no-std` build goes hand-in-hand with [minimal builds] because typical embedded
|
||||
hardware (the primary target for `no-std`) has limited storage.
|
||||
|
||||
```admonish warning "Nightly required"
|
||||
|
||||
Currently, [`no_std`] requires the nightly compiler due to the crates that it uses.
|
||||
```
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
Rhai allocates, so the first thing that must be included in any `no-std` project is
|
||||
an allocator crate, such as [`wee_alloc`](https://crates.io/crates/wee_alloc).
|
||||
|
||||
Then there is the need to set up proper error/panic handlers.
|
||||
The following example uses `panic = "abort"` and `wee_alloc` as the allocator.
|
||||
|
||||
```rust
|
||||
// Set up for no-std.
|
||||
#![no_std]
|
||||
|
||||
// The following no-std features are usually needed.
|
||||
#![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)]
|
||||
|
||||
// Set up the global allocator.
|
||||
extern crate alloc;
|
||||
extern crate wee_alloc;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
// Rust needs a CRT runtime on Windows when compiled with MSVC.
|
||||
#[cfg(all(windows, target_env = "msvc"))]
|
||||
#[link(name = "msvcrt")]
|
||||
#[link(name = "libcmt")]
|
||||
extern "C" {}
|
||||
|
||||
// Set up panic and error handlers
|
||||
#[alloc_error_handler]
|
||||
fn err_handler(_: core::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
#[lang = "panic_impl"]
|
||||
extern "C" fn rust_begin_panic(_: &core::panic::PanicInfo) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
extern "C" fn eh_personality() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_register_frames() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_unregister_frames() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn _Unwind_Resume() {}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
// ... main program ...
|
||||
}
|
||||
```
|
||||
|
||||
```admonish example.small "Samples"
|
||||
|
||||
Check out the [`no-std` sample applications]({{rootUrl}}/start/examples/rust.html#no-std-examples)
|
||||
for different operating environments.
|
||||
```
|
204
_archive/rhai_engine/rhaibook/start/builds/performance.md
Normal file
204
_archive/rhai_engine/rhaibook/start/builds/performance.md
Normal file
@@ -0,0 +1,204 @@
|
||||
Performance Build
|
||||
=================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
|
||||
Some features are for performance. In order to squeeze out the maximum performance from Rhai, the
|
||||
following features should be considered:
|
||||
|
||||
| Feature | Description | Rationale |
|
||||
| -------------------- | ------------------------------------------------------ | ------------------------ |
|
||||
| [`only_i32`] | support only a single `i32` integer type | reduce data size |
|
||||
| [`no_float`] | remove support for floating-point numbers | reduce code size |
|
||||
| [`f32_float`] | set floating-point numbers (if not disabled) to 32-bit | reduce data size |
|
||||
| [`no_closure`] | remove support for [variables] sharing | no need for data locking |
|
||||
| [`unchecked`] | disable all safety [checks][checked] | remove checking code |
|
||||
| [`no_module`] | disable loading external [modules] | reduce code size |
|
||||
| [`no_position`] | disable position tracking during parsing | reduce data size |
|
||||
| [`no_custom_syntax`] | disable [custom syntax] | reduce code size |
|
||||
|
||||
When the above feature flags are used, performance may increase by around 15-20%.
|
||||
|
||||
~~~admonish info.small "See also: Benchmarks"
|
||||
|
||||
See Rhai performance [benchmarks].
|
||||
~~~
|
||||
|
||||
|
||||
Unchecked Build
|
||||
---------------
|
||||
|
||||
By default, Rhai provides a [_Don't Panic_](https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic)
|
||||
guarantee and prevents malicious scripts from bringing down the host. Any panic can be considered a bug.
|
||||
|
||||
For maximum performance, however, these [safety] checks can be turned off via the [`unchecked`] feature.
|
||||
|
||||
|
||||
Fast Operators Mode
|
||||
-------------------
|
||||
|
||||
Make sure that [_Fast Operators_ Mode][options], which is enabled by default, is on. It ignores any
|
||||
user [overloading][operator overloading] of [built-in operators].
|
||||
|
||||
For operator-heavy scripts, this may provide a substantial speed-up.
|
||||
|
||||
|
||||
Use Only One Integer Type
|
||||
-------------------------
|
||||
|
||||
If only a single integer type is needed in scripts – most of the time this is the case –
|
||||
it is best to avoid registering lots of functions related to other integer types that will never be used.
|
||||
As a result, [`Engine`] creation will be faster because fewer functions need to be loaded.
|
||||
|
||||
The [`only_i32`] and [`only_i64`] features disable all integer types except `i32` or `i64` respectively.
|
||||
|
||||
|
||||
Use Only 32-Bit Numbers
|
||||
-----------------------
|
||||
|
||||
If only 32-bit integers are needed – again, most of the time this is the case – turn on [`only_i32`].
|
||||
Under this feature, only `i32` is supported as a built-in integer type and no others.
|
||||
|
||||
On 64-bit targets this may not gain much, but on certain 32-bit targets this improves performance
|
||||
due to 64-bit arithmetic requiring more CPU cycles to complete.
|
||||
|
||||
|
||||
Minimize Size of `Dynamic`
|
||||
--------------------------
|
||||
|
||||
Turning on [`f32_float`] (or [`no_float`]) and [`only_i32`] on 32-bit targets makes the critical
|
||||
[`Dynamic`] data type only 8 bytes long for 32-bit targets.
|
||||
|
||||
Normally [`Dynamic`] needs to be up 12-16 bytes long in order to hold an `i64` or `f64`.
|
||||
|
||||
A smaller [`Dynamic`] helps performance due to better cache efficiency.
|
||||
|
||||
|
||||
Use `ImmutableString`
|
||||
---------------------
|
||||
|
||||
Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type.
|
||||
This is mainly to avoid excessive cloning when passing function arguments.
|
||||
|
||||
Rhai's internal string type is [`ImmutableString`] (basically `Rc<SmartString>` or
|
||||
`Arc<SmartString>` depending on the [`sync`] feature). It is cheap to clone, but expensive to modify
|
||||
(a new copy of the string must be made in order to change it).
|
||||
|
||||
Therefore, functions taking `String` parameters should use [`ImmutableString`] or `&str`
|
||||
(maps to [`ImmutableString`]) for the best performance with Rhai.
|
||||
|
||||
|
||||
Disable Capturing in Closures
|
||||
-----------------------------
|
||||
|
||||
```admonish info.side "Anonymous functions still work"
|
||||
|
||||
[Anonymous functions] continue to work even under [`no_closure`].
|
||||
|
||||
Only capturing of external shared [variables] is disabled.
|
||||
```
|
||||
|
||||
Support for [closures] that capture _shared_ [variables] adds material overhead to script evaluation.
|
||||
|
||||
This is because every data access must be checked whether it is a shared value and, if so,
|
||||
take a read lock before reading it.
|
||||
|
||||
As the vast majority of [variables] are _not_ shared, needless to say this is a non-trivial
|
||||
performance overhead.
|
||||
|
||||
Use [`no_closure`] to disable support for [closures] to optimize the hot path because it no longer
|
||||
needs to take locks for shared data.
|
||||
|
||||
|
||||
Disable Position
|
||||
----------------
|
||||
|
||||
For embedded scripts that are not expected to cause errors, the [`no_position`] feature can be used
|
||||
to disable position tracking during parsing.
|
||||
|
||||
No line number/character position information is kept for error reporting purposes.
|
||||
|
||||
This may result in a slightly fast build due to elimination of code related to position tracking.
|
||||
|
||||
|
||||
Avoid Cloning
|
||||
-------------
|
||||
|
||||
### Use `&mut` functions
|
||||
|
||||
Rhai values are typically _cloned_ when passed around, especially into [function] calls.
|
||||
Large data structures may incur material cloning overhead.
|
||||
|
||||
Some functions accept the first parameter as a mutable reference (i.e. `&mut`), for example
|
||||
_methods_ for [custom types], and may avoid potentially-costly cloning.
|
||||
|
||||
### Compound assignment
|
||||
|
||||
For example, the `+=` (append) compound assignment takes a mutable reference to the [variable] while
|
||||
the corresponding `+` (add) assignment usually doesn't. The difference in performance can be huge:
|
||||
|
||||
```rust
|
||||
let x = create_some_very_big_and_expensive_type();
|
||||
|
||||
x = x + 1;
|
||||
// ^ 'x' is cloned here
|
||||
|
||||
// The above is equivalent to:
|
||||
let temp_value = x.clone() + 1;
|
||||
x = temp_value;
|
||||
|
||||
x += 1; // <- 'x' is NOT cloned
|
||||
```
|
||||
|
||||
### Use `take`
|
||||
|
||||
Another example: use the `take` function to extract a value out of a variable (replacing it with
|
||||
[`()`]) without cloning.
|
||||
|
||||
```rust
|
||||
let x = create_some_very_big_and_expensive_type();
|
||||
|
||||
let y = x; // <- 'x' is cloned here
|
||||
|
||||
let y = x.take(); // <- 'x' is NOT cloned
|
||||
```
|
||||
|
||||
```admonish tip "Tip: Simple variable references are already optimized"
|
||||
|
||||
Rhai's script [optimizer][script optimization] is usually smart enough to _rewrite_ function calls
|
||||
into [_method-call_]({{rootUrl}}/rust/methods.md) style or [_compound assignment_]({{rootUrl}}/language/assignment-op.md)
|
||||
style to take advantage of this.
|
||||
|
||||
However, there are limits to its intelligence, and only **simple variable references** are optimized.
|
||||
|
||||
~~~rust
|
||||
x = x + 1; // <- this statement...
|
||||
|
||||
x += 1; // ... is rewritten as this
|
||||
|
||||
x[y] = x[y] + 1; // <- but this is not, so this is MUCH slower...
|
||||
|
||||
x[y] += 1; // ... than this
|
||||
|
||||
some_func(x, 1); // <- this statement...
|
||||
|
||||
x.some_func(1); // ... is rewritten as this
|
||||
|
||||
some_func(x[y], 1); // <- but this is not, so 'x[y]` is cloned
|
||||
~~~
|
||||
```
|
||||
|
||||
|
||||
Short Variable Names for 32-Bit Systems
|
||||
---------------------------------------
|
||||
|
||||
On 32-bit systems, [variable] and [constant] names longer than 11 ASCII characters incur additional
|
||||
allocation overhead.
|
||||
|
||||
This is particularly true for local variables inside a hot loop, where they are created and destroyed
|
||||
in rapid succession.
|
||||
|
||||
Therefore, avoid long [variable] and [constant] names that are over this limit.
|
||||
|
||||
On 64-bit systems, this limit is raised to 23 ASCII characters, which is almost always adequate.
|
116
_archive/rhai_engine/rhaibook/start/builds/wasm.md
Normal file
116
_archive/rhai_engine/rhaibook/start/builds/wasm.md
Normal file
@@ -0,0 +1,116 @@
|
||||
WebAssembly (WASM) Build
|
||||
========================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
```admonish question.side.wide "But why?"
|
||||
|
||||
There is already a fast and powerful scripting language that integrates nicely with WASM – **JavaScript**.
|
||||
|
||||
Anyhow, do it because you _can_!
|
||||
```
|
||||
|
||||
It is possible to use Rhai when compiling to WebAssembly (WASM).
|
||||
|
||||
This yields a scripting engine (and language) that can be run in a standard web browser,
|
||||
among other places.
|
||||
|
||||
```admonish warning "Unavailable features"
|
||||
|
||||
When building for WASM, certain features will not be available,
|
||||
such as the script file APIs and loading [modules] from external script files.
|
||||
```
|
||||
|
||||
```admonish example "Sample"
|
||||
|
||||
Check out the [_Online Playground_]({{rootUrl}}/tools/playground.md) project which is driven
|
||||
by a Rhai [`Engine`] compiled into WASM.
|
||||
```
|
||||
|
||||
|
||||
JavaScript Interop
|
||||
------------------
|
||||
|
||||
Specify either of the [`wasm-bindgen`] or [`stdweb`] features when building for WASM that requires
|
||||
interop with JavaScript. This selects the appropriate JavaScript interop layer to use.
|
||||
|
||||
It is still possible to compile for WASM without either [`wasm-bindgen`] or [`stdweb`],
|
||||
but then the interop code must then be explicitly provided.
|
||||
|
||||
|
||||
Target Environments
|
||||
-------------------
|
||||
|
||||
~~~admonish abstract "WASI: `wasm32-wasi`"
|
||||
|
||||
There is no particular setting to tweak when building for WASI.
|
||||
~~~
|
||||
|
||||
~~~admonish abstract "JavaScript: `wasm32-unknown-unknown` + `wasm-bindgen`/`stdweb`"
|
||||
|
||||
Rhai requires a system-provided source of random numbers (for hashing).
|
||||
|
||||
Such random number source is available from JavaScript (implied by `wasm-bindgen` or `stdweb`).
|
||||
|
||||
The `js` feature on the [`getrandom`](https://crates.io/crates/getrandom) crate is
|
||||
enabled automatically to provide the random number source.
|
||||
See also: <https://docs.rs/getrandom/latest/getrandom/#webassembly-support> for details.
|
||||
~~~
|
||||
|
||||
~~~admonish warning "Raw: `wasm32-unknown-unknown`"
|
||||
|
||||
Rhai requires a system-provided source of random numbers (for hashing).
|
||||
|
||||
Non-JavaScript/non-browser environments may not have random numbers available, so it is necessary to
|
||||
opt out of `default-features` in order to enable [static hashing] which uses fixed (non-random) keys.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = { version = "{{version}}", default-features = false, features = [ "std" ] }
|
||||
```
|
||||
~~~
|
||||
|
||||
|
||||
Size
|
||||
----
|
||||
|
||||
Also look into [minimal builds] to reduce generated WASM size.
|
||||
|
||||
A typical, full-featured Rhai scripting engine compiles to a single WASM32 file that is less than
|
||||
400KB (non-gzipped).
|
||||
|
||||
When excluding features that are marginal in WASM environment, the gzipped payload can be shrunk further.
|
||||
|
||||
Standard [packages][built-in packages] can also be excluded to yield additional size savings.
|
||||
|
||||
|
||||
Speed
|
||||
-----
|
||||
|
||||
In benchmark tests, a WASM build runs scripts roughly 30% slower than a native optimized release build.
|
||||
|
||||
|
||||
Common Features
|
||||
---------------
|
||||
|
||||
Some Rhai functionalities are not necessary in a WASM environment, so the following features
|
||||
are typically used for a WASM build:
|
||||
|
||||
| Feature | Description |
|
||||
| :----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`wasm-bindgen`] or [`stdweb`] | use [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) or [`stdweb`](https://crates.io/crates/stdweb) as the JavaScript interop layer, omit if using custom interop code |
|
||||
| [`unchecked`] | when a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely – the web app must terminate it itself |
|
||||
| [`only_i32`] | WASM supports 32-bit and 64-bit integers, but most scripts will only need 32-bit |
|
||||
| [`f32_float`] | WASM supports 32-bit single-precision and 64-bit double-precision floating-point numbers, but single-precision is usually fine for most uses |
|
||||
| [`no_module`] | a WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts |
|
||||
| [`no_custom_syntax`] | if [custom syntax] is not used, this results in a small size saving |
|
||||
|
||||
The following features are typically _not_ used because they don't make sense in a WASM build:
|
||||
|
||||
| Feature | Why unnecessary |
|
||||
| :-----------: | ----------------------------------------------------------------------------------------------------- |
|
||||
| [`sync`] | WASM is single-threaded |
|
||||
| [`no_std`] | `std` lib works fine with WASM |
|
||||
| [`metadata`] | WASM usually doesn't need access to Rhai functions metadata |
|
||||
| [`internals`] | WASM usually doesn't need to access Rhai internal data structures, unless you are walking the [`AST`] |
|
||||
| [`debugging`] | unless debugging is needed |
|
Reference in New Issue
Block a user