7.3 KiB
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%.
See Rhai performance [benchmarks].
Unchecked Build
By default, Rhai provides a 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
[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:
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.
let x = create_some_very_big_and_expensive_type();
let y = x; // <- 'x' is cloned here
let y = x.take(); // <- 'x' is NOT cloned
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.