Skip to content

Commit 8b3296e

Browse files
chore(RUN-1012): infrastructure to increase Wasm64 heap memory size (dfinity#3385)
This PR prepares infrastructure to increase Wasm64 heap memory size allowing Wasm64 canisters to run with different heap memory sizes alongside the Wasm32 canisters. Note that this PR is a no-op for now and not changing any functionality, as the Wasm64 heap memory size is still kept at 4GiB. The intent is that this only allows that in the future the change can happen seamlessly, by only changing a constant.
1 parent 83c1bbf commit 8b3296e

File tree

19 files changed

+221
-32
lines changed

19 files changed

+221
-32
lines changed

rs/config/src/embedders.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::time::Duration;
33
use ic_base_types::NumBytes;
44
use ic_registry_subnet_type::SubnetType;
55
use ic_sys::PAGE_SIZE;
6-
use ic_types::{NumInstructions, NumOsPages, MAX_STABLE_MEMORY_IN_BYTES, MAX_WASM_MEMORY_IN_BYTES};
6+
use ic_types::{
7+
NumInstructions, NumOsPages, MAX_STABLE_MEMORY_IN_BYTES, MAX_WASM64_MEMORY_IN_BYTES,
8+
MAX_WASM_MEMORY_IN_BYTES,
9+
};
710
use serde::{Deserialize, Serialize};
811

912
use crate::flag_status::FlagStatus;
@@ -245,6 +248,9 @@ pub struct Config {
245248
/// The maximum size of the wasm heap memory.
246249
pub max_wasm_memory_size: NumBytes,
247250

251+
/// The maximum size of the wasm heap memory for Wasm64 canisters.
252+
pub max_wasm64_memory_size: NumBytes,
253+
248254
/// The maximum size of the stable memory.
249255
pub max_stable_memory_size: NumBytes,
250256
}
@@ -284,6 +290,7 @@ impl Config {
284290
dirty_page_copy_overhead: DIRTY_PAGE_COPY_OVERHEAD,
285291
wasm_max_size: WASM_MAX_SIZE,
286292
max_wasm_memory_size: NumBytes::new(MAX_WASM_MEMORY_IN_BYTES),
293+
max_wasm64_memory_size: NumBytes::new(MAX_WASM64_MEMORY_IN_BYTES),
287294
max_stable_memory_size: NumBytes::new(MAX_STABLE_MEMORY_IN_BYTES),
288295
wasm64_dirty_page_overhead_multiplier: WASM64_DIRTY_PAGE_OVERHEAD_MULTIPLIER,
289296
}

rs/config/src/execution_environment.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::embedders::Config as EmbeddersConfig;
22
use crate::flag_status::FlagStatus;
33
use ic_base_types::{CanisterId, NumSeconds};
44
use ic_types::{
5-
Cycles, NumBytes, NumInstructions, MAX_STABLE_MEMORY_IN_BYTES, MAX_WASM_MEMORY_IN_BYTES,
5+
Cycles, NumBytes, NumInstructions, MAX_STABLE_MEMORY_IN_BYTES, MAX_WASM64_MEMORY_IN_BYTES,
6+
MAX_WASM_MEMORY_IN_BYTES,
67
};
78
use serde::{Deserialize, Serialize};
89
use std::{str::FromStr, time::Duration};
@@ -204,7 +205,12 @@ pub struct Config {
204205
pub subnet_memory_reservation: NumBytes,
205206

206207
/// The maximum amount of memory that can be utilized by a single canister.
207-
pub max_canister_memory_size: NumBytes,
208+
/// running in Wasm32 mode.
209+
pub max_canister_memory_size_wasm32: NumBytes,
210+
211+
/// The maximum amount of memory that can be utilized by a single canister.
212+
/// running in Wasm64 mode.
213+
pub max_canister_memory_size_wasm64: NumBytes,
208214

209215
/// The soft limit on the subnet-wide number of callbacks. Beyond this limit,
210216
/// canisters are only allowed to make downstream calls up to their individual
@@ -342,9 +348,12 @@ impl Default for Config {
342348
subnet_wasm_custom_sections_memory_capacity:
343349
SUBNET_WASM_CUSTOM_SECTIONS_MEMORY_CAPACITY,
344350
subnet_memory_reservation: SUBNET_MEMORY_RESERVATION,
345-
max_canister_memory_size: NumBytes::new(
351+
max_canister_memory_size_wasm32: NumBytes::new(
346352
MAX_STABLE_MEMORY_IN_BYTES + MAX_WASM_MEMORY_IN_BYTES,
347353
),
354+
max_canister_memory_size_wasm64: NumBytes::new(
355+
MAX_STABLE_MEMORY_IN_BYTES + MAX_WASM64_MEMORY_IN_BYTES,
356+
),
348357
subnet_callback_soft_limit: SUBNET_CALLBACK_SOFT_LIMIT,
349358
canister_guaranteed_callback_quota: CANISTER_GUARANTEED_CALLBACK_QUOTA,
350359
default_provisional_cycles_balance: Cycles::new(100_000_000_000_000),

rs/drun/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ async fn drun_main() -> Result<(), String> {
6767
.embedders_config
6868
.feature_flags
6969
.best_effort_responses = FlagStatus::Enabled;
70-
hypervisor_config.embedders_config.max_wasm_memory_size = MAIN_MEMORY_CAPACITY;
71-
hypervisor_config.max_canister_memory_size =
72-
hypervisor_config.embedders_config.max_wasm_memory_size
70+
hypervisor_config.embedders_config.max_wasm64_memory_size = MAIN_MEMORY_CAPACITY;
71+
hypervisor_config.max_canister_memory_size_wasm64 =
72+
hypervisor_config.embedders_config.max_wasm64_memory_size
7373
+ hypervisor_config.embedders_config.max_stable_memory_size;
7474

7575
let cfg = Config::load_with_default(&source, default_config).unwrap_or_else(|err| {

rs/embedders/benches/embedders_bench/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn initialize_execution_test(
5757
if is_wasm64 {
5858
test = test.with_wasm64();
5959
// Set memory size to 8 GiB for Wasm64.
60-
test = test.with_max_wasm_memory_size(NumBytes::from(8 * 1024 * 1024 * 1024));
60+
test = test.with_max_wasm64_memory_size(NumBytes::from(8 * 1024 * 1024 * 1024));
6161
}
6262
let mut test = test.build();
6363

rs/embedders/src/wasm_utils.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use ic_types::{methods::WasmMethod, NumInstructions};
1414
use ic_wasm_types::{BinaryEncodedWasm, WasmInstrumentationError};
1515
use serde::{Deserialize, Serialize};
1616

17-
use self::{instrumentation::instrument, validation::validate_wasm_binary};
17+
use self::{
18+
instrumentation::instrument, validation::has_wasm64_memory, validation::validate_wasm_binary,
19+
};
1820
use crate::wasmtime_embedder::StoreData;
1921
use crate::{serialized_module::SerializedModule, CompilationResult, WasmtimeEmbedder};
2022
use wasmtime::InstancePre;
@@ -204,6 +206,13 @@ fn validate_and_instrument(
204206
config: &EmbeddersConfig,
205207
) -> HypervisorResult<(WasmValidationDetails, InstrumentationOutput)> {
206208
let (wasm_validation_details, module) = validate_wasm_binary(wasm, config)?;
209+
// Instrumentation bytemap depends on the Wasm memory size, so for larger heaps we need
210+
// to pass in the corresponding Wasm64 heap memory size.
211+
let max_wasm_memory_size = if has_wasm64_memory(&module) {
212+
config.max_wasm64_memory_size
213+
} else {
214+
config.max_wasm_memory_size
215+
};
207216
let instrumentation_output = instrument(
208217
module,
209218
config.cost_to_compile_wasm_instruction,
@@ -212,7 +221,7 @@ fn validate_and_instrument(
212221
config.metering_type,
213222
config.subnet_type,
214223
config.dirty_page_overhead,
215-
config.max_wasm_memory_size,
224+
max_wasm_memory_size,
216225
config.max_stable_memory_size,
217226
)?;
218227
Ok((wasm_validation_details, instrumentation_output))

rs/embedders/src/wasm_utils/validation.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,11 @@ fn validate_function_section(
10681068
Ok(())
10691069
}
10701070

1071+
// Checks if the module has a Wasm64 memory.
1072+
pub fn has_wasm64_memory(module: &Module) -> bool {
1073+
module.memories.first().is_some_and(|m| m.memory64)
1074+
}
1075+
10711076
// Checks that the initial size of the wasm (heap) memory is not larger than
10721077
// the allowed maximum size. This is only needed for Wasm64, because in Wasm32 this
10731078
// is checked by Wasmtime.
@@ -1552,7 +1557,14 @@ pub(super) fn validate_wasm_binary<'a>(
15521557
validate_data_section(&module)?;
15531558
validate_global_section(&module, config.max_globals)?;
15541559
validate_function_section(&module, config.max_functions)?;
1555-
validate_initial_wasm_memory_size(&module, config.max_wasm_memory_size)?;
1560+
// The maximum Wasm memory size is different for Wasm32 and Wasm64 and
1561+
// each needs to be validated accordingly.
1562+
let max_wasm_memory_size = if has_wasm64_memory(&module) {
1563+
config.max_wasm64_memory_size
1564+
} else {
1565+
config.max_wasm_memory_size
1566+
};
1567+
validate_initial_wasm_memory_size(&module, max_wasm_memory_size)?;
15561568
let (largest_function_instruction_count, max_complexity) = validate_code_section(&module)?;
15571569
let wasm_metadata = validate_custom_section(&module, config)?;
15581570
Ok((

rs/embedders/tests/validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ fn test_wasm64_initial_wasm_memory_size_validation() {
11781178
..Default::default()
11791179
};
11801180
let allowed_wasm_memory_size_in_pages =
1181-
embedders_config.max_wasm_memory_size.get() / WASM_PAGE_SIZE as u64;
1181+
embedders_config.max_wasm64_memory_size.get() / WASM_PAGE_SIZE as u64;
11821182
let declared_wasm_memory_size_in_pages = allowed_wasm_memory_size_in_pages + 10;
11831183
let wasm = wat2wasm(&format!(
11841184
r#"(module

rs/embedders/tests/wasmtime_embedder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3032,7 +3032,7 @@ fn large_wasm64_stable_read_write_test() {
30323032
config.feature_flags.wasm64 = FlagStatus::Enabled;
30333033
config.feature_flags.wasm_native_stable_memory = FlagStatus::Enabled;
30343034
// Declare a large heap.
3035-
config.max_wasm_memory_size = NumBytes::from(10 * gb);
3035+
config.max_wasm64_memory_size = NumBytes::from(10 * gb);
30363036

30373037
let mut instance = WasmtimeInstanceBuilder::new()
30383038
.with_config(config)

rs/execution_environment/benches/lib/src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ where
281281
};
282282

283283
// Set up larger heap, of 8GB for the Wasm64 feature.
284-
embedders_config.max_wasm_memory_size = NumBytes::from(8 * 1024 * 1024 * 1024);
284+
embedders_config.max_wasm64_memory_size = NumBytes::from(8 * 1024 * 1024 * 1024);
285285

286286
let config = Config {
287287
embedders_config,

rs/execution_environment/src/canister_manager.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ pub(crate) struct CanisterMgrConfig {
121121
pub(crate) own_subnet_id: SubnetId,
122122
pub(crate) own_subnet_type: SubnetType,
123123
pub(crate) max_controllers: usize,
124-
pub(crate) max_canister_memory_size: NumBytes,
124+
pub(crate) max_canister_memory_size_wasm32: NumBytes,
125+
pub(crate) max_canister_memory_size_wasm64: NumBytes,
125126
pub(crate) rate_limiting_of_instructions: FlagStatus,
126127
rate_limiting_of_heap_delta: FlagStatus,
127128
heap_delta_rate_limit: NumBytes,
@@ -141,7 +142,8 @@ impl CanisterMgrConfig {
141142
own_subnet_type: SubnetType,
142143
max_controllers: usize,
143144
compute_capacity: usize,
144-
max_canister_memory_size: NumBytes,
145+
max_canister_memory_size_wasm32: NumBytes,
146+
max_canister_memory_size_wasm64: NumBytes,
145147
rate_limiting_of_instructions: FlagStatus,
146148
allocatable_capacity_in_percent: usize,
147149
rate_limiting_of_heap_delta: FlagStatus,
@@ -160,7 +162,8 @@ impl CanisterMgrConfig {
160162
max_controllers,
161163
compute_capacity: (compute_capacity * allocatable_capacity_in_percent.min(100) / 100)
162164
as u64,
163-
max_canister_memory_size,
165+
max_canister_memory_size_wasm32,
166+
max_canister_memory_size_wasm64,
164167
rate_limiting_of_instructions,
165168
rate_limiting_of_heap_delta,
166169
heap_delta_rate_limit,
@@ -2195,7 +2198,10 @@ impl CanisterManager {
21952198
let mut new_canister =
21962199
CanisterState::new(system_state, new_execution_state, scheduler_state);
21972200
let new_memory_usage = new_canister.memory_usage();
2198-
let memory_allocation_given = canister.memory_limit(self.config.max_canister_memory_size);
2201+
2202+
let memory_allocation_given =
2203+
canister.memory_limit(self.get_max_canister_memory_size(is_wasm64_execution));
2204+
21992205
if new_memory_usage > memory_allocation_given {
22002206
return (
22012207
Err(CanisterManagerError::NotEnoughMemoryAllocationGiven {
@@ -2336,6 +2342,16 @@ impl CanisterManager {
23362342
);
23372343
Ok(())
23382344
}
2345+
2346+
/// Depending on the canister architecture (Wasm32 or Wasm64), returns the
2347+
/// maximum memory size that can be allocated by a canister.
2348+
pub(crate) fn get_max_canister_memory_size(&self, is_wasm64_execution: bool) -> NumBytes {
2349+
if is_wasm64_execution {
2350+
self.config.max_canister_memory_size_wasm64
2351+
} else {
2352+
self.config.max_canister_memory_size_wasm32
2353+
}
2354+
}
23392355
}
23402356

23412357
#[derive(Eq, PartialEq, Debug)]

0 commit comments

Comments
 (0)