Skip to content

Commit edb50e9

Browse files
committed
runtime: Enable Cranelift OptLevel::Speed for WASM compilation
Switch the default Cranelift optimization level from `None` to `Speed`, improving WASM handler execution performance. The optimization level is configurable via the `GRAPH_WASM_OPT_LEVEL` environment variable (valid values: `none`, `speed`, `speed_and_size`; default: `speed`). This is safe because Cranelift adheres to the Wasm spec and NaN canonicalization is already enabled. The increased compilation time is a one-time cost per module, amortized over thousands of triggers.
1 parent 629f2f7 commit edb50e9

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

graph/src/env/mappings.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ pub struct EnvVarsMapping {
8282
/// Maximum backoff time for FDS requests. Set by
8383
/// `GRAPH_FDS_MAX_BACKOFF` in seconds, defaults to 600.
8484
pub fds_max_backoff: Duration,
85+
86+
/// Cranelift optimization level for WASM compilation.
87+
///
88+
/// Set by the environment variable `GRAPH_WASM_OPT_LEVEL`. Valid values
89+
/// are `none`, `speed`, and `speed_and_size`. The default value is
90+
/// `speed`.
91+
pub wasm_opt_level: WasmOptLevel,
92+
}
93+
94+
/// Cranelift optimization level for WASM compilation. Maps to
95+
/// `wasmtime::OptLevel` without introducing a dependency on wasmtime.
96+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
97+
pub enum WasmOptLevel {
98+
None,
99+
Speed,
100+
SpeedAndSize,
85101
}
86102

87103
// This does not print any values avoid accidentally leaking any sensitive env vars
@@ -91,6 +107,32 @@ impl fmt::Debug for EnvVarsMapping {
91107
}
92108
}
93109

110+
impl fmt::Display for WasmOptLevel {
111+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112+
match self {
113+
WasmOptLevel::None => write!(f, "none"),
114+
WasmOptLevel::Speed => write!(f, "speed"),
115+
WasmOptLevel::SpeedAndSize => write!(f, "speed_and_size"),
116+
}
117+
}
118+
}
119+
120+
impl FromStr for WasmOptLevel {
121+
type Err = String;
122+
123+
fn from_str(s: &str) -> Result<Self, Self::Err> {
124+
match s.to_lowercase().as_str() {
125+
"none" => Ok(WasmOptLevel::None),
126+
"speed" => Ok(WasmOptLevel::Speed),
127+
"speed_and_size" => Ok(WasmOptLevel::SpeedAndSize),
128+
_ => Err(format!(
129+
"invalid GRAPH_WASM_OPT_LEVEL '{}', expected 'none', 'speed', or 'speed_and_size'",
130+
s
131+
)),
132+
}
133+
}
134+
}
135+
94136
impl TryFrom<InnerMappingHandlers> for EnvVarsMapping {
95137
type Error = anyhow::Error;
96138

@@ -121,6 +163,7 @@ impl TryFrom<InnerMappingHandlers> for EnvVarsMapping {
121163
disable_declared_calls: x.disable_declared_calls.0,
122164
store_errors_are_nondeterministic: x.store_errors_are_nondeterministic.0,
123165
fds_max_backoff: Duration::from_secs(x.fds_max_backoff),
166+
wasm_opt_level: x.wasm_opt_level,
124167
};
125168
Ok(vars)
126169
}
@@ -164,6 +207,8 @@ pub struct InnerMappingHandlers {
164207
store_errors_are_nondeterministic: EnvVarBoolean,
165208
#[envconfig(from = "GRAPH_FDS_MAX_BACKOFF", default = "600")]
166209
fds_max_backoff: u64,
210+
#[envconfig(from = "GRAPH_WASM_OPT_LEVEL", default = "speed")]
211+
wasm_opt_level: WasmOptLevel,
167212
}
168213

169214
fn validate_ipfs_cache_location(path: PathBuf) -> Result<PathBuf, anyhow::Error> {

graph/src/env/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use semver::Version;
1111

1212
use self::graphql::*;
1313
use self::mappings::*;
14+
15+
pub use self::mappings::WasmOptLevel;
1416
use self::store::*;
1517
use crate::{
1618
components::{store::BlockNumber, subgraph::SubgraphVersionSwitchingMode},

runtime/wasm/src/mapping.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,14 +291,19 @@ impl ValidModule {
291291
.map_err(|_| anyhow!("Failed to inject gas counter"))?;
292292
let raw_module = parity_module.into_bytes()?;
293293

294-
// We currently use Cranelift as a compilation engine. Cranelift is an optimizing compiler,
295-
// but that should not cause determinism issues since it adheres to the Wasm spec. Still we
296-
// turn off optional optimizations to be conservative.
294+
// We use Cranelift as a compilation engine. Cranelift is an optimizing compiler, but that
295+
// should not cause determinism issues since it adheres to the Wasm spec and NaN
296+
// canonicalization is enabled below. The optimization level is configurable via
297+
// GRAPH_WASM_OPT_LEVEL (default: speed).
297298
let mut config = wasmtime::Config::new();
298299
config.strategy(wasmtime::Strategy::Cranelift);
299300
config.epoch_interruption(true);
300301
config.cranelift_nan_canonicalization(true); // For NaN determinism.
301-
config.cranelift_opt_level(wasmtime::OptLevel::None);
302+
config.cranelift_opt_level(match ENV_VARS.mappings.wasm_opt_level {
303+
graph::env::WasmOptLevel::None => wasmtime::OptLevel::None,
304+
graph::env::WasmOptLevel::Speed => wasmtime::OptLevel::Speed,
305+
graph::env::WasmOptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize,
306+
});
302307
config.max_wasm_stack(ENV_VARS.mappings.max_stack_size);
303308
config.async_support(true);
304309

0 commit comments

Comments
 (0)