diff --git a/Cargo.lock b/Cargo.lock index 9b6b23ad04e..aba84f3477d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,6 +111,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -886,6 +895,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -2878,6 +2893,12 @@ dependencies = [ "toml 0.8.23", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cbor4ii" version = "0.3.3" @@ -2989,6 +3010,33 @@ dependencies = [ "windows-link", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cid" version = "0.9.0" @@ -3658,6 +3706,41 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap 4.5.54", + "criterion-plot", + "itertools 0.13.0", + "num-traits", + "oorandom", + "page_size", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools 0.13.0", +] + [[package]] name = "critical-section" version = "1.2.0" @@ -7407,6 +7490,7 @@ dependencies = [ "assert_matches", "gear-sandbox-env", "gear-sandbox-interface", + "gear-wasmtime-cache", "gear-workspace-hack", "log", "parity-scale-codec", @@ -7436,6 +7520,7 @@ dependencies = [ "defer", "environmental", "gear-sandbox-env", + "gear-wasmtime-cache", "gear-workspace-hack", "log", "parity-scale-codec", @@ -7669,6 +7754,20 @@ dependencies = [ "which", ] +[[package]] +name = "gear-wasmtime-cache" +version = "1.10.0" +dependencies = [ + "criterion", + "gear-core", + "gear-workspace-hack", + "loom", + "lru 0.16.3", + "tempfile", + "tracing", + "wasmtime", +] + [[package]] name = "gear-weight-diff" version = "1.0.0" @@ -7814,6 +7913,7 @@ dependencies = [ "indexmap 2.14.0", "ipnet", "itertools 0.10.5", + "itertools 0.13.0", "itertools 0.14.0", "js-sys", "jsonrpsee", @@ -8039,6 +8139,7 @@ dependencies = [ "wasmtime-internal-cranelift", "winnow", "x25519-dalek", + "zerocopy", "zeroize", ] @@ -8071,6 +8172,21 @@ dependencies = [ "sp-staking", ] +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result 0.4.1", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -8507,6 +8623,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "handlebars" version = "5.1.2" @@ -11164,6 +11291,19 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lru" version = "0.12.5" @@ -12246,6 +12386,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -13806,6 +13952,34 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "polkavm" version = "0.9.3" @@ -19281,6 +19455,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.10.0" @@ -21261,6 +21445,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 74e3f3ab771..ae70ce0d30d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,6 +148,7 @@ cargo_metadata = "0.20.0" clap = "4.5.8" colored = "2.1.0" const-str = "0.5" +criterion = "0.8.2" crossbeam = "0.8.4" defer = "0.2.1" derive_more = { version = "2.0.1", default-features = false, features = [ @@ -291,6 +292,7 @@ gear-wasm-builder = { path = "sdk/wasm-builder", default-features = false } gear-wasm-optimizer = { path = "sdk/wasm-optimizer", default-features = false } gear-wasm-gen = { path = "protocol/wasm-gen" } gear-wasm-instrument = { path = "protocol/wasm-instrument", default-features = false } +gear-wasmtime-cache = { version = "1.10.0", path = "protocol/wasmtime-cache" } junit-common = { path = "vara/tools/regression-analysis/junit-common" } actor-system-error = { path = "protocol/actor-system-error" } pallet-gear = { path = "vara/pallets/gear", default-features = false } @@ -566,6 +568,7 @@ nix = "0.26.4" # gear-lazy-pages ipc-channel = "0.19.0" # lazy-pages-fuzzer itertools = { version = "0.13", default-features = false } # sdk/wasm-builder libp2p = "=0.51.4" # vara/sdk/gcli (same version as sc-consensus) +loom = "0.7.2" # protocol/wasmtime-cache mimalloc = { version = "0.1.46", default-features = false } # vara/node/cli nacl = "0.5.3" # vara/sdk/gcli libfuzzer-sys = "0.4" # vara/tools/runtime-fuzzer/fuzz @@ -603,6 +606,7 @@ ip_network = "0.4.1" # ethexe/network [workspace.lints.rust] unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(fuzz)', + 'cfg(loom)', 'cfg(substrate_runtime)', ] } diff --git a/ethexe/processor/Cargo.toml b/ethexe/processor/Cargo.toml index ad7ffba71f3..fb2b8515c2e 100644 --- a/ethexe/processor/Cargo.toml +++ b/ethexe/processor/Cargo.toml @@ -25,7 +25,7 @@ core-processor.workspace = true futures.workspace = true thiserror.workspace = true -wasmtime = "44.0.1" +wasmtime.workspace = true log.workspace = true parity-scale-codec = { workspace = true, features = ["std", "derive"] } sp-allocator = { workspace = true, features = ["std"] } diff --git a/ethexe/processor/src/host/mod.rs b/ethexe/processor/src/host/mod.rs index a06efe7a6ce..db43cc97c47 100644 --- a/ethexe/processor/src/host/mod.rs +++ b/ethexe/processor/src/host/mod.rs @@ -91,7 +91,7 @@ impl InstanceCreator { .macos_use_mach_ports(false); let engine = wasmtime::Engine::new(&config)?; - let module = wasmtime::Module::new(&engine, runtime)?; + let module = wasmtime::Module::new(&engine, &runtime)?; let mut linker = wasmtime::Linker::new(&engine); api::allocator::link(&mut linker)?; diff --git a/protocol/sandbox/Cargo.toml b/protocol/sandbox/Cargo.toml index 98422ddc27e..88c7cfb152a 100644 --- a/protocol/sandbox/Cargo.toml +++ b/protocol/sandbox/Cargo.toml @@ -25,6 +25,7 @@ gear-sandbox-env.workspace = true # embedded executor only wasmtime = { workspace = true, optional = true } +gear-wasmtime-cache = { workspace = true, optional = true } gear-workspace-hack.workspace = true @@ -43,5 +44,6 @@ std = [ "gear-sandbox-interface/std", "gear-sandbox-env/std", "wasmtime", + "gear-wasmtime-cache", ] strict = [] diff --git a/protocol/sandbox/host/Cargo.toml b/protocol/sandbox/host/Cargo.toml index 120ca9b6be2..225e407dd71 100644 --- a/protocol/sandbox/host/Cargo.toml +++ b/protocol/sandbox/host/Cargo.toml @@ -27,6 +27,7 @@ sp-allocator = { workspace = true, features = ["std"] } sp-wasm-interface-common = { workspace = true, features = ["std"] } gear-sandbox-env = { workspace = true, features = ["std"] } region.workspace = true +gear-wasmtime-cache.workspace = true gear-workspace-hack.workspace = true diff --git a/protocol/sandbox/host/src/sandbox/wasmtime_backend.rs b/protocol/sandbox/host/src/sandbox/wasmtime_backend.rs index 3e4374da997..486993d84b2 100644 --- a/protocol/sandbox/host/src/sandbox/wasmtime_backend.rs +++ b/protocol/sandbox/host/src/sandbox/wasmtime_backend.rs @@ -16,8 +16,11 @@ use crate::{ use gear_sandbox_env::{GLOBAL_NAME_GAS, HostError, Instantiate, WasmReturnValue}; use parity_scale_codec::{Decode, Encode}; use sp_wasm_interface_common::{Pointer, ReturnValue, Value, WordSize}; -use std::rc::{Rc, Weak}; -use wasmtime::{AsContextMut, Engine, ExternType, Linker, MemoryType, Module, Val}; +use std::{ + rc::{Rc, Weak}, + sync::OnceLock, +}; +use wasmtime::{AsContextMut, Engine, ExternType, Linker, MemoryType, Val}; type Store = wasmtime::Store>; pub type StoreRefCell = store_refcell::StoreRefCell; @@ -93,18 +96,26 @@ impl Drop for Backend { impl Backend { pub fn new() -> Self { - let cache = wasmtime::CacheConfig::new(); - let cache = wasmtime::Cache::new(cache).expect("invalid cache configuration"); - let mut config = wasmtime::Config::default(); - config - .strategy(wasmtime::Strategy::Winch) - .cache(Some(cache)) - // Gear lazy-pages chains Unix signal handlers. Disable Wasmtime's - // macOS Mach-port trap handler so sandbox traps stay delegatable - // through the signal-handler chain. - .macos_use_mach_ports(false); - let engine = Engine::new(&config).expect("invalid engine configuration"); - let store = Store::new(&engine, None); + // The backend is cleared if the store changes or the clear counter is triggered, + // so keep the engine always the same. This lets `gear_wasmtime_cache::get` + // return a cloned module instead of re-serializing it, + // which is around 20 times faster (see `gear-wasmtime-cache` benches). + static ENGINE: OnceLock = OnceLock::new(); + let engine = ENGINE.get_or_init(|| { + let cache = wasmtime::CacheConfig::new(); + let cache = wasmtime::Cache::new(cache).expect("invalid cache configuration"); + let mut config = wasmtime::Config::default(); + config + .strategy(wasmtime::Strategy::Winch) + .cache(Some(cache)) + // Gear lazy-pages chains Unix signal handlers. Disable Wasmtime's + // macOS Mach-port trap handler so sandbox traps stay delegatable + // through the signal-handler chain. + .macos_use_mach_ports(false); + Engine::new(&config).expect("invalid engine configuration") + }); + + let store = Store::new(engine, None); Backend { store: Rc::new(StoreRefCell::new(store)), @@ -243,8 +254,8 @@ pub fn instantiate( ) -> Result { let mut store = context.store().borrow_mut(); - let module = - Module::new(store.engine(), wasm).map_err(|_| InstantiationError::ModuleDecoding)?; + let module = gear_wasmtime_cache::get(store.engine(), wasm) + .map_err(|_| InstantiationError::ModuleDecoding)?; let mut linker = Linker::new(store.engine()); for import in module.imports() { diff --git a/protocol/sandbox/src/embedded_executor.rs b/protocol/sandbox/src/embedded_executor.rs index cc61e6406d4..33ebe5c233a 100644 --- a/protocol/sandbox/src/embedded_executor.rs +++ b/protocol/sandbox/src/embedded_executor.rs @@ -9,10 +9,10 @@ use crate::{ use alloc::string::String; use gear_sandbox_env::GLOBAL_NAME_GAS; use sp_wasm_interface_common::HostPointer; -use std::{collections::btree_map::BTreeMap, marker::PhantomData}; +use std::{collections::btree_map::BTreeMap, marker::PhantomData, sync::OnceLock}; use wasmtime::{ - Cache, CacheConfig, Config, Engine, ExternType, Global, Linker, MemoryType, Module, - StoreContext, StoreContextMut, error::Context, + Cache, CacheConfig, Config, Engine, ExternType, Global, Linker, MemoryType, StoreContext, + StoreContextMut, error::Context, }; /// The target used for logging. @@ -50,20 +50,27 @@ impl Store { impl SandboxStore for Store { fn new(state: T) -> Self { - let cache = Cache::new(CacheConfig::new()).expect("invalid cache configuration"); - - let mut config = Config::new(); - config - .max_wasm_stack(16 * 1024 * 1024) // make stack size bigger for fuzzer - .async_stack_size(16 * 1024 * 1024) - .strategy(wasmtime::Strategy::Winch) - .cache(Some(cache)) - // Keep sandbox traps on Unix signals on macOS: Gear lazy-pages - // installs and chains SIGSEGV handlers, which cannot delegate to - // Wasmtime's Mach-port trap handler. - .macos_use_mach_ports(false); - let engine = Engine::new(&config).expect("invalid engine configuration"); - let store = wasmtime::Store::new(&engine, InnerState::new(state)); + // The backend is cleared if the store changes or the clear counter is triggered, + // so keep the engine always the same. This lets `gear_wasmtime_cache::get` + // return a cloned module instead of re-serializing it, + // which is around 20 times faster (see `gear-wasmtime-cache` benches). + static ENGINE: OnceLock = OnceLock::new(); + let engine = ENGINE.get_or_init(|| { + let cache = Cache::new(CacheConfig::new()).expect("invalid cache configuration"); + let mut config = Config::new(); + config + .max_wasm_stack(16 * 1024 * 1024) // make stack size bigger for fuzzer + .async_stack_size(16 * 1024 * 1024) + .strategy(wasmtime::Strategy::Winch) + .cache(Some(cache)) + // Keep sandbox traps on Unix signals on macOS: Gear lazy-pages + // installs and chains SIGSEGV handlers, which cannot delegate to + // Wasmtime's Mach-port trap handler. + .macos_use_mach_ports(false); + Engine::new(&config).expect("invalid engine configuration") + }); + + let store = wasmtime::Store::new(engine, InnerState::new(state)); Self { inner: store } } @@ -268,7 +275,7 @@ impl super::SandboxInstance for Instance { code: &[u8], env_def_builder: &Self::EnvironmentBuilder, ) -> Result, Error> { - let module = Module::new(store.engine(), code) + let module = gear_wasmtime_cache::get(store.engine(), code) .inspect_err(|e| log::trace!(target: TARGET, "Failed to create module: {e}")) .map_err(|_e| Error::Module)?; diff --git a/protocol/wasmtime-cache/Cargo.toml b/protocol/wasmtime-cache/Cargo.toml new file mode 100644 index 00000000000..dc45c079d46 --- /dev/null +++ b/protocol/wasmtime-cache/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "gear-wasmtime-cache" +description = "Wasmtime executor's in-memory module cache used by Gear nodes" +documentation = "https://docs.rs/gear-wasmtime-cache" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +tracing.workspace = true +lru.workspace = true +wasmtime.workspace = true +gear-core.workspace = true +gear-workspace-hack.workspace = true + +[target.'cfg(not(loom))'.dev-dependencies] +criterion.workspace = true +tempfile.workspace = true + +[target.'cfg(loom)'.dev-dependencies] +loom.workspace = true + +[[bench]] +name = "lru_cache" +harness = false diff --git a/protocol/wasmtime-cache/benches/lru_cache.rs b/protocol/wasmtime-cache/benches/lru_cache.rs new file mode 100644 index 00000000000..0646f8b9385 --- /dev/null +++ b/protocol/wasmtime-cache/benches/lru_cache.rs @@ -0,0 +1,50 @@ +// Copyright (C) Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +use criterion::{BatchSize, Criterion, Throughput, criterion_group, criterion_main}; +use std::hint::black_box; +use wasmtime::{Cache, CacheConfig, Config, Engine, Module, Strategy}; + +const BIG_WASM: &[u8] = include_bytes!(concat!( + env!("GEAR_WORKSPACE_DIR"), + "/sdk/examples/big-wasm/big.wasm" +)); + +fn create_engine() -> Engine { + let cache_dir = tempfile::tempdir().expect("temp dir is created").keep(); + let mut cache = CacheConfig::new(); + cache.with_directory(cache_dir.join("wasmtime-cache")); + let cache = Cache::new(cache).expect("cache config is valid"); + + let mut config = Config::new(); + config.strategy(Strategy::Winch).cache(Some(cache)); + Engine::new(&config).expect("engine config is valid") +} + +fn lru_cache(c: &mut Criterion) { + let code = BIG_WASM; + + let engine = create_engine(); + + let mut group = c.benchmark_group("new_module"); + group.throughput(Throughput::Elements(1)); + + group.bench_function("disk_cache", |b| { + b.iter(|| Module::new(&engine, black_box(code)).unwrap()) + }); + + group.bench_function("lru_cache", |b| { + b.iter(|| gear_wasmtime_cache::get(&engine, black_box(code)).unwrap()) + }); + + group.bench_function("engine_changed", |b| { + b.iter_batched( + create_engine, + |engine| gear_wasmtime_cache::get(&engine, black_box(code)).unwrap(), + BatchSize::SmallInput, + ); + }); +} + +criterion_group!(benches, lru_cache); +criterion_main!(benches); diff --git a/protocol/wasmtime-cache/src/lib.rs b/protocol/wasmtime-cache/src/lib.rs new file mode 100644 index 00000000000..72e722a46bf --- /dev/null +++ b/protocol/wasmtime-cache/src/lib.rs @@ -0,0 +1,272 @@ +// Copyright (C) Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +//! Wasmtime module cache. +//! +//! The cache uses a per-code "single flight" protocol. The first thread that +//! misses the LRU for a code hash records that hash in `compiling`, drops the +//! lock, and compiles the module. Threads requesting the same hash wait on a +//! condition variable, while threads requesting other hashes can reserve their +//! own compile slots and proceed independently. +//! +//! A `CompilePermit` represents ownership of one in-progress compile. Dropping +//! it always removes the hash from `compiling` and wakes waiters, so both +//! successful compilation and early errors unblock the next thread. + +#[cfg(all(loom, test))] +use loom::sync::{Condvar, Mutex}; +#[cfg(not(all(loom, test)))] +use std::sync::{Condvar, Mutex}; + +use gear_core::ids::{CodeId, prelude::CodeIdExt}; +use lru::LruCache; +use std::{collections::HashSet, num::NonZeroUsize, sync::OnceLock}; +use wasmtime::{Engine, Module, error::Context}; + +const MODULES_CACHE_CAPACITY: NonZeroUsize = NonZeroUsize::new(1024).unwrap(); + +struct Cache { + state: Mutex, + module_ready: Condvar, +} + +struct CacheState { + modules: LruCache, + // Codes currently being compiled outside the mutex. A code is present here + // only while its owner holds a `CompilePermit`. + compiling: HashSet, +} + +impl Cache { + fn new() -> Self { + Self { + state: Mutex::new(CacheState { + modules: LruCache::new(MODULES_CACHE_CAPACITY), + compiling: HashSet::new(), + }), + module_ready: Condvar::new(), + } + } + + fn get(&self, engine: &Engine, code: &[u8]) -> wasmtime::Result { + let code_id = CodeId::generate(code); + + let _permit = match self.reserve_compile(code_id, engine)? { + Ok(permit) => permit, + Err(module) => return Ok(module), + }; + + tracing::trace!("create wasmtime module because of missed LRU cache"); + + let module = Module::new(engine, code).context("failed to create module")?; + + let mut state = self.state.lock().unwrap(); + let old_module = state.modules.put(code_id, module.clone()); + debug_assert!(old_module.is_none()); + + Ok(ModuleFrom::New(module)) + } + + fn reserve_compile( + &self, + code_id: CodeId, + engine: &Engine, + ) -> wasmtime::Result, ModuleFrom>> { + let mut state = self.state.lock().unwrap(); + + loop { + // Re-check after every wake-up: another thread may have inserted + // the module while we slept, or the condvar may wake spuriously. + if let Some(module) = Self::cached_module(&mut state, engine, code_id)? { + return Ok(Err(module)); + } + + // Inserting the code makes this thread the only compiler for this + // code. Different codes do not block each other. + if state.compiling.insert(code_id) { + return Ok(Ok(CompilePermit { + cache: self, + code_id, + })); + } + + state = self.module_ready.wait(state).unwrap(); + } + } + + fn cached_module( + state: &mut CacheState, + engine: &Engine, + code_id: CodeId, + ) -> wasmtime::Result> { + let Some(module) = state.modules.get(&code_id) else { + return Ok(None); + }; + + tracing::trace!("load wasmtime module from LRU cache"); + + if Engine::same(module.engine(), engine) { + Ok(Some(ModuleFrom::Lru(module.clone()))) + } else { + tracing::trace!("reserialize module because of changed engine"); + let module = match module + .serialize() + .context("failed to serialize module") + .and_then(|module| unsafe { + Module::deserialize(engine, &module).context("failed to deserialize module") + }) { + Ok(module) => module, + Err(error) => { + tracing::trace!( + "failed to reserialize module for changed engine, recompiling: {error:?}" + ); + state.modules.pop(&code_id); + // Treat an engine-incompatible serialized module as a miss: + // the caller will reserve a compile slot and run + // `Module::new(engine, code)` outside the mutex. + return Ok(None); + } + }; + let old_module = state.modules.put(code_id, module.clone()); + debug_assert!(old_module.is_some()); + Ok(Some(ModuleFrom::EngineChanged(module))) + } + } + + fn finish_compile(&self, code_id: CodeId) { + { + let mut state = self.state.lock().unwrap(); + debug_assert!(state.compiling.remove(&code_id)); + } + + self.module_ready.notify_all(); + } +} + +/// RAII marker for one in-progress compile. +/// +/// The permit is created while holding `Cache::state`, then compilation happens +/// without the mutex. Its `Drop` implementation clears `compiling` and notifies +/// waiters, including when `Module::new` returns an error. +struct CompilePermit<'a> { + cache: &'a Cache, + code_id: CodeId, +} + +impl Drop for CompilePermit<'_> { + fn drop(&mut self) { + self.cache.finish_compile(self.code_id); + } +} + +enum ModuleFrom { + Lru(Module), + EngineChanged(Module), + New(Module), +} + +/// Returns a compiled Wasmtime module, using an in-memory LRU cache on hits. +pub fn get(engine: &Engine, code: &[u8]) -> wasmtime::Result { + static CACHE: OnceLock = OnceLock::new(); + + let cache = CACHE.get_or_init(Cache::new); + match cache.get(engine, code)? { + ModuleFrom::Lru(module) | ModuleFrom::EngineChanged(module) | ModuleFrom::New(module) => { + Ok(module) + } + } +} + +#[cfg(not(loom))] +#[cfg(test)] +mod tests { + use super::*; + use wasmtime::{Config, ModuleVersionStrategy}; + + const EMPTY_WASM: &[u8] = b"\x00asm\x01\x00\x00\x00"; + + fn engine_with_module_version(version: &str) -> Engine { + let mut config = Config::new(); + config + .module_version(ModuleVersionStrategy::Custom(version.to_string())) + .expect("module version is valid"); + Engine::new(&config).expect("engine config is valid") + } + + #[test] + fn smoke() { + let engine = Engine::default(); + + let cache = Cache::new(); + + let module = cache.get(&engine, EMPTY_WASM).expect("module compiles"); + assert!(matches!(module, ModuleFrom::New(_))); + + let module = cache + .get(&engine, EMPTY_WASM) + .expect("module loads from cache"); + assert!(matches!(module, ModuleFrom::Lru(_))); + + let module = cache + .get(&Engine::default(), EMPTY_WASM) + .expect("module loads from cache"); + assert!(matches!(module, ModuleFrom::EngineChanged(_))); + } + + #[test] + fn compiles_when_cached_module_cannot_be_deserialized_for_engine() { + let cache = Cache::new(); + + let module = cache + .get(&engine_with_module_version("first"), EMPTY_WASM) + .expect("module compiles"); + assert!(matches!(module, ModuleFrom::New(_))); + + let module = cache + .get(&engine_with_module_version("second"), EMPTY_WASM) + .expect("module compiles after deserialize miss"); + assert!(matches!(module, ModuleFrom::New(_))); + } +} + +#[cfg(loom)] +#[cfg(test)] +mod tests_loom { + use super::*; + use loom::{sync::Arc, thread}; + + const EMPTY_WASM: &[u8] = b"\x00asm\x01\x00\x00\x00"; + + #[test] + fn loom_environment() { + loom::model(|| { + let engine = Engine::default(); + let cache = Arc::new(Cache::new()); + let mut threads = Vec::new(); + + for i in 0..2 { + let cache = cache.clone(); + let engine = engine.clone(); + + let handle = thread::Builder::new() + .stack_size(4 * 1024 * 1024) + .name(format!("test-thread-{i}")) + .spawn(move || cache.get(&engine, EMPTY_WASM).expect("module compiles")) + .expect("failed to spawn thread"); + threads.push(handle); + } + + let mut new = 0; + let mut lru = 0; + for handle in threads { + match handle.join().expect("thread panicked") { + ModuleFrom::New(_) => new += 1, + ModuleFrom::Lru(_) => lru += 1, + ModuleFrom::EngineChanged(_) => panic!("engine should not change"), + } + } + + assert_eq!((new, lru), (1, 1)); + }); + } +} diff --git a/scripts/hakari-post-process.sh b/scripts/hakari-post-process.sh index 8304213e15a..734ae036b42 100755 --- a/scripts/hakari-post-process.sh +++ b/scripts/hakari-post-process.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash # Post-processes gear-workspace-hack/Cargo.toml after `cargo hakari generate` -# to wrap all dependencies in cfg(not(target_arch = "wasm32")). +# to wrap all dependencies in cfgs that exclude wasm32 and loom builds. # -# This ensures that on wasm32 builds, the workspace-hack crate has zero -# dependencies (just a #![no_std] stub), while on native builds it retains -# full feature unification for optimal compilation. +# This ensures that on wasm32 and loom builds, the workspace-hack crate has zero +# dependencies (just a #![no_std] stub), while on normal native builds it +# retains full feature unification for optimal compilation. # # Usage: ./scripts/hakari-post-process.sh # Run after: cargo hakari generate @@ -19,21 +19,21 @@ if [ ! -f "$WORKSPACE_HACK" ]; then exit 1 fi -CFG="target.'cfg(not(target_arch = \"wasm32\"))'" +CFG="target.'cfg(not(any(target_arch = \"wasm32\", loom)))'" +X86_64_LINUX_CFG="target.'cfg(all(target_arch = \"x86_64\", target_vendor = \"unknown\", target_os = \"linux\", target_env = \"gnu\", not(any(target_arch = \"wasm32\", loom))))'" +AARCH64_LINUX_CFG="target.'cfg(all(target_arch = \"aarch64\", target_vendor = \"unknown\", target_os = \"linux\", target_env = \"gnu\", not(any(target_arch = \"wasm32\", loom))))'" +AARCH64_MACOS_CFG="target.'cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\", target_os = \"macos\", not(any(target_arch = \"wasm32\", loom))))'" -# Replace: -# - [dependencies.X] -> [target.'cfg(...)'.dependencies.X] (manual section) -# - [dependencies] -> [target.'cfg(...)'.dependencies] (hakari section) -# - [build-dependencies] -> [target.'cfg(...)'.build-dependencies] -# -# Does NOT touch [target.TRIPLE.*] sections (already platform-specific). -# Idempotent: already-wrapped headers won't match the patterns. +# Hakari currently emits only top-level dependency sections and exact platform +# target sections. Wrap those sections so the workspace-hack graph is absent +# from wasm32 and loom builds. sed -i.bak -E \ - -e "s/^\[dependencies\.([^\]]+)\](\s*.*)$/[${CFG}.dependencies.\1]\2/" \ - -e "s/^\[dependencies\](\s*.*)$/[${CFG}.dependencies]\1/" \ - -e "s/^\[build-dependencies\](\s*.*)$/[${CFG}.build-dependencies]\1/" \ + -e "s/^\[(dependencies|build-dependencies)\]$/[${CFG}.\1]/" \ + -e "s/^\[target\.x86_64-unknown-linux-gnu\.(dependencies|build-dependencies)\]$/[${X86_64_LINUX_CFG}.\1]/" \ + -e "s/^\[target\.aarch64-unknown-linux-gnu\.(dependencies|build-dependencies)\]$/[${AARCH64_LINUX_CFG}.\1]/" \ + -e "s/^\[target\.aarch64-apple-darwin\.(dependencies|build-dependencies)\]$/[${AARCH64_MACOS_CFG}.\1]/" \ "$WORKSPACE_HACK" rm -f "${WORKSPACE_HACK}.bak" -echo "Post-processed $WORKSPACE_HACK: all deps wrapped in cfg(not(target_arch = \"wasm32\"))" +echo "Post-processed $WORKSPACE_HACK: generated deps/build-deps wrapped for wasm32/loom" diff --git a/scripts/src/test.sh b/scripts/src/test.sh index 2d9adf9af33..1a479fa7883 100755 --- a/scripts/src/test.sh +++ b/scripts/src/test.sh @@ -105,6 +105,7 @@ doc_test() { time_consuming_tests() { # cargo test -p demo-fungible-token --no-fail-fast --release -- --nocapture --ignored cargo test -p gear-wasm-builder --no-fail-fast "$@" -- --nocapture --ignored + LOOM_MAX_PREEMPTIONS=3 RUSTFLAGS="--cfg loom" cargo test -p gear-wasmtime-cache --no-fail-fast --release -- --nocapture } ensure_binary() { diff --git a/utils/crates-io/src/lib.rs b/utils/crates-io/src/lib.rs index 45cf93dcce7..dcdefe20beb 100644 --- a/utils/crates-io/src/lib.rs +++ b/utils/crates-io/src/lib.rs @@ -61,6 +61,7 @@ pub const STACKED_DEPENDENCIES: &[&str] = &[ "builtins-common", "gear-utils", "gear-common", + "gear-wasmtime-cache", "gear-sandbox-host", "gear-lazy-pages-common", "gear-lazy-pages", diff --git a/utils/gear-workspace-hack/Cargo.toml b/utils/gear-workspace-hack/Cargo.toml index 6d3d84d25d4..7eee68f341c 100644 --- a/utils/gear-workspace-hack/Cargo.toml +++ b/utils/gear-workspace-hack/Cargo.toml @@ -17,204 +17,204 @@ publish = false # they have features like `runtime-benchmarks` and `try-runtime` # so we cannot, for example, run `cargo build -p gear-cli` without `--all-features` -[dependencies.frame-executive] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-executive] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.frame-support] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-support] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" features = ["experimental"] -[dependencies.frame-try-runtime] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.frame-try-runtime] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-authority-discovery] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-authority-discovery] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-authorship] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-authorship] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-babe] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-babe] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-bags-list] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-bags-list] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-balances] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-balances] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-bounties] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-bounties] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-child-bounties] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-child-bounties] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-conviction-voting] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-conviction-voting] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-election-provider-multi-phase] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-election-provider-multi-phase] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-grandpa] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-grandpa] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-identity] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-identity] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-im-online] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-im-online] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-multisig] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-multisig] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-nomination-pools] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-nomination-pools] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-offences] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-offences] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-preimage] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-preimage] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-proxy] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-proxy] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-ranked-collective] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-ranked-collective] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-referenda] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-referenda] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-scheduler] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-scheduler] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-session] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-session] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["historical", "std"] -[dependencies.pallet-sudo] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-sudo] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-timestamp] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-timestamp] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-transaction-payment] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-transaction-payment] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-treasury] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-treasury] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-utility] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-utility] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-vesting] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-vesting] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.pallet-whitelist] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.pallet-whitelist] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["std"] -[dependencies.sc-client-db] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.sc-client-db] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" default-features = false features = ["rocksdb", "test-helpers"] -[dependencies.sc-service] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies.sc-service] git = "https://github.com/gear-tech/polkadot-sdk.git" branch = "gear-polkadot-stable2409-updated-wasmtime" features = ["test-helpers"] ### BEGIN HAKARI SECTION -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.dependencies] ahash = { version = "0.8" } alloy = { version = "2", features = ["kzg", "node-bindings", "provider-anvil-api", "provider-ws", "rpc-types-beacon", "rpc-types-eth", "signer-mnemonic"] } alloy-chains = { version = "0.2" } @@ -499,7 +499,7 @@ winnow = { version = "0.7" } x25519-dalek = { version = "2", features = ["static_secrets"] } zeroize = { version = "1", features = ["derive", "std"] } -[target.'cfg(not(target_arch = "wasm32"))'.build-dependencies] +[target.'cfg(not(any(target_arch = "wasm32", loom)))'.build-dependencies] ahash = { version = "0.8" } alloy = { version = "2", features = ["kzg", "node-bindings", "provider-anvil-api", "provider-ws", "rpc-types-beacon", "rpc-types-eth", "signer-mnemonic"] } alloy-chains = { version = "0.2" } @@ -795,12 +795,13 @@ winnow = { version = "0.7" } x25519-dalek = { version = "2", features = ["static_secrets"] } zeroize = { version = "1", features = ["derive", "std"] } -[target.x86_64-unknown-linux-gnu.dependencies] +[target.'cfg(all(target_arch = "x86_64", target_vendor = "unknown", target_os = "linux", target_env = "gnu", not(any(target_arch = "wasm32", loom))))'.dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } linux-raw-sys = { version = "0.11", default-features = false, features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std", "prctl"] } @@ -817,13 +818,15 @@ rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } -[target.x86_64-unknown-linux-gnu.build-dependencies] +[target.'cfg(all(target_arch = "x86_64", target_vendor = "unknown", target_os = "linux", target_env = "gnu", not(any(target_arch = "wasm32", loom))))'.build-dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } linux-raw-sys = { version = "0.11", default-features = false, features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std", "prctl"] } @@ -840,13 +843,15 @@ rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } -[target.aarch64-unknown-linux-gnu.dependencies] +[target.'cfg(all(target_arch = "aarch64", target_vendor = "unknown", target_os = "linux", target_env = "gnu", not(any(target_arch = "wasm32", loom))))'.dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } linux-raw-sys = { version = "0.11", default-features = false, features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std", "prctl"] } @@ -863,13 +868,15 @@ rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } -[target.aarch64-unknown-linux-gnu.build-dependencies] +[target.'cfg(all(target_arch = "aarch64", target_vendor = "unknown", target_os = "linux", target_env = "gnu", not(any(target_arch = "wasm32", loom))))'.build-dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } linux-raw-sys = { version = "0.11", default-features = false, features = ["auxvec", "elf", "errno", "general", "ioctl", "no_std", "prctl"] } @@ -886,13 +893,15 @@ rustls-webpki = { version = "0.103", features = ["aws-lc-rs", "ring"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } -[target.aarch64-apple-darwin.dependencies] +[target.'cfg(all(target_arch = "aarch64", target_vendor = "apple", target_os = "macos", not(any(target_arch = "wasm32", loom))))'.dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } miniz_oxide = { version = "0.8", default-features = false, features = ["simd", "with-alloc"] } @@ -907,13 +916,15 @@ security-framework-sys = { version = "2", features = ["OSX_10_14"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } -[target.aarch64-apple-darwin.build-dependencies] +[target.'cfg(all(target_arch = "aarch64", target_vendor = "apple", target_os = "macos", not(any(target_arch = "wasm32", loom))))'.build-dependencies] crossbeam-epoch = { version = "0.9" } errno = { version = "0.3" } hickory-proto = { version = "0.25", default-features = false, features = ["mdns", "tokio"] } hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "http2", "logging", "ring", "tls12", "webpki-tokio"] } hyper-util = { version = "0.1", default-features = false, features = ["client-proxy"] } +itertools-594e8ee84c453af0 = { package = "itertools", version = "0.13" } libc = { version = "0.2", default-features = false, features = ["extra_traits"] } librocksdb-sys = { version = "0.11", features = ["jemalloc", "snappy"] } miniz_oxide = { version = "0.8", default-features = false, features = ["simd", "with-alloc"] } @@ -928,5 +939,6 @@ security-framework-sys = { version = "2", features = ["OSX_10_14"] } sha-1 = { version = "0.10", features = ["asm"] } tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "logging", "ring", "tls12"] } unicode-normalization = { version = "0.1" } +zerocopy = { version = "0.8", default-features = false, features = ["derive", "simd"] } ### END HAKARI SECTION