Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions rs/config/src/embedders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@ pub(crate) const DEFAULT_MAX_DIRTY_PAGES_WITHOUT_OPTIMIZATION: usize = (GIB as u
/// Scheduling overhead for copying dirty pages, in instructions.
pub(crate) const DIRTY_PAGE_COPY_OVERHEAD: NumInstructions = NumInstructions::new(3_000);

/// The overhead for dirty pages in Wasm64.
pub const WASM64_DIRTY_PAGE_OVERHEAD_MULTIPLIER: u64 = 4;

const KIB: u64 = 1024;
const GIB: u64 = KIB * KIB * KIB;

Expand Down Expand Up @@ -245,9 +242,6 @@ pub struct Config {
/// The dirty page copying overhead, in instructions.
pub dirty_page_copy_overhead: NumInstructions,

/// The dirty page overhead factor for Wasm64.
pub wasm64_dirty_page_overhead_multiplier: u64,

/// The maximum allowed size for an uncompressed canister Wasm module.
pub wasm_max_size: NumBytes,

Expand Down Expand Up @@ -298,7 +292,6 @@ impl Config {
max_wasm_memory_size: NumBytes::new(MAX_WASM_MEMORY_IN_BYTES),
max_wasm64_memory_size: NumBytes::new(MAX_WASM64_MEMORY_IN_BYTES),
max_stable_memory_size: NumBytes::new(MAX_STABLE_MEMORY_IN_BYTES),
wasm64_dirty_page_overhead_multiplier: WASM64_DIRTY_PAGE_OVERHEAD_MULTIPLIER,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion rs/config/src/subnet_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ pub const DEFAULT_REFERENCE_SUBNET_SIZE: usize = 13;
pub const SEV_REFERENCE_SUBNET_SIZE: usize = 7;

/// Costs for each newly created dirty page in stable memory.
const DEFAULT_DIRTY_PAGE_OVERHEAD: NumInstructions = NumInstructions::new(1_000);
pub const DEFAULT_DIRTY_PAGE_OVERHEAD: NumInstructions = NumInstructions::new(5_000);

/// Accumulated priority reset interval, rounds.
///
Expand Down
1 change: 1 addition & 0 deletions rs/embedders/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ rust_test(
crate = ":embedders",
deps = [
# Keep sorted.
"//rs/config",
"//rs/interfaces",
"//rs/test_utilities",
"//rs/test_utilities/types",
Expand Down
1 change: 1 addition & 0 deletions rs/embedders/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ assert_matches = { workspace = true }
canister-test = { path = "../rust_canisters/canister_test" }
criterion = { workspace = true }
embedders_bench = { path = "benches/embedders_bench" }
ic-config = {path = "../config"}
ic-registry-routing-table = { path = "../registry/routing_table" }
ic-test-utilities = { path = "../test_utilities" }
ic-test-utilities-embedders = { path = "../test_utilities/embedders" }
Expand Down
30 changes: 0 additions & 30 deletions rs/embedders/src/wasm_utils/system_api_replacements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,21 +912,6 @@ pub(super) fn replacement_functions(
function_index: injected_functions.internal_trap,
},
End,
// Decrement instruction counter to charge for dirty pages
LocalGet {
local_index: DIRTY_PAGE_COUNT,
},
I64ExtendI32U,
I64Const {
value: dirty_page_overhead.get().try_into().unwrap(),
},
I64Mul,
// Bounds check above should guarantee that we don't
// overflow as the over head is a small constant.
Call {
function_index: decr_instruction_counter_fn,
},
Drop,
// perform memory fill
LocalGet {
local_index: BYTEMAP_START,
Expand Down Expand Up @@ -1155,21 +1140,6 @@ pub(super) fn replacement_functions(
function_index: injected_functions.internal_trap,
},
End,
// Decrement instruction counter to charge for dirty pages
LocalGet {
local_index: DIRTY_PAGE_COUNT,
},
I64ExtendI32U,
I64Const {
value: dirty_page_overhead.get().try_into().unwrap(),
},
I64Mul,
// Bounds check above should guarantee that we don't
// overflow as the over head is a small constant.
Call {
function_index: decr_instruction_counter_fn,
},
Drop,
// perform memory fill
LocalGet {
local_index: BYTEMAP_START,
Expand Down
19 changes: 8 additions & 11 deletions rs/embedders/src/wasmtime_embedder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,12 @@ impl WasmtimeEmbedder {
bytemap_name: Some(STABLE_BYTEMAP_MEMORY_NAME),
memory: stable_memory.clone(),
memory_type: CanisterMemoryType::Stable,
// Wasm native stable memory will always be tracked by a
// bytemap within the wasm module.
dirty_page_tracking: DirtyPageTracking::Ignore,
// Wasm native stable memory is tracked by a
// bytemap within the wasm module, but that's used
// only for limiting the memory. The deterministic
// memory tracker accounts for page fault charging,
// same as for the heap pages.
dirty_page_tracking,
});

result
Expand Down Expand Up @@ -639,20 +642,14 @@ impl WasmtimeEmbedder {
main_memory_type = WasmMemoryType::Wasm64;
}

let dirty_page_overhead = match main_memory_type {
WasmMemoryType::Wasm32 => self.config.dirty_page_overhead,
WasmMemoryType::Wasm64 => NumInstructions::from(
self.config.dirty_page_overhead.get()
* self.config.wasm64_dirty_page_overhead_multiplier,
),
};
let dirty_page_overhead = self.config.dirty_page_overhead;

let memory_trackers = sigsegv_memory_tracker(
memories,
&mut *store,
self.log.clone(),
self.config.feature_flags.deterministic_memory_tracker,
/*dirty_page_overhead*/ NumInstructions::new(1),
self.config.dirty_page_overhead,
subtract_instruction_counter,
);

Expand Down
27 changes: 12 additions & 15 deletions rs/embedders/tests/instrumentation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ic_config::embedders::{Config as EmbeddersConfig, MeteringType};
use ic_config::flag_status::FlagStatus;
use ic_config::subnet_config::SchedulerConfig;
use ic_config::subnet_config::{DEFAULT_DIRTY_PAGE_OVERHEAD, SchedulerConfig};
use ic_embedders::wasm_utils;
use ic_embedders::{
WasmtimeEmbedder,
Expand Down Expand Up @@ -287,9 +287,7 @@ fn instr_used(instance: &mut WasmtimeInstance) -> u64 {
/// - `n_heap_wasm_pages`: pages first *written* on the heap.
/// Each triggers `mark_wasm_page_accessed` + `mark_wasm_page_dirty`:
/// 2 × (WASM_PAGE_SIZE / OS_PAGE_SIZE) = 2 × 16 = 32 instructions.
/// - `n_stable_wasm_pages`: pages first *accessed* in stable memory.
/// Stable memory uses `DirtyPageTracking::Ignore`, so only
/// `mark_wasm_page_accessed` fires: 16 instructions per page.
/// - `n_stable_wasm_pages`: same as for heap: 32 instructions per page.
///
/// Returns 0 when the deterministic memory tracker is disabled.
fn deterministic_tracker_overhead(n_heap_wasm_pages: u64, n_stable_wasm_pages: u64) -> u64 {
Expand All @@ -300,7 +298,7 @@ fn deterministic_tracker_overhead(n_heap_wasm_pages: u64, n_stable_wasm_pages: u
{
let os_pages_per_wasm_page = (WASM_PAGE_SIZE_IN_BYTES / PAGE_SIZE) as u64;
n_heap_wasm_pages * 2 * os_pages_per_wasm_page
+ n_stable_wasm_pages * os_pages_per_wasm_page
+ n_stable_wasm_pages * 2 * os_pages_per_wasm_page
} else {
0
}
Expand Down Expand Up @@ -813,23 +811,20 @@ fn run_charge_for_dirty_heap(wasm_memory_type: WasmMemoryType) {
},
wasm_memory_type,
);
let mut cd = SchedulerConfig::application_subnet()
let cd = SchedulerConfig::application_subnet()
.dirty_page_overhead
.get();

if let WasmMemoryType::Wasm64 = wasm_memory_type {
cd *= EmbeddersConfig::default().wasm64_dirty_page_overhead_multiplier;
}

// Both stores target Wasm page 0 (bytes 0 and 4096 are within the 64KB page),
// so only one heap page-first-write event occurs.
let overhead = deterministic_tracker_overhead(1, 0);
let dirty_page_overhead = DEFAULT_DIRTY_PAGE_OVERHEAD.get();

let instructions_used = instr_used(&mut instance);
// Function is 1 instruction.
assert_eq!(
instructions_used,
1 + 5 * cc + cg + 2 * cs + cl + 2 * cd + overhead
1 + 5 * cc + cg + 2 * cs + cl + 2 * cd + overhead * dirty_page_overhead
);

// Now run the same with insufficient instructions
Expand Down Expand Up @@ -872,7 +867,7 @@ fn run_charge_for_dirty_stable64_test() {
(memory (export "memory") 10)
)"#;

let mut instance = new_instance_for_stable_write(wat, 10000);
let mut instance = new_instance_for_stable_write(wat, 1_000_000);
let res = instance.run(func_ref("test")).unwrap();

let g = &res.exported_globals;
Expand Down Expand Up @@ -945,12 +940,12 @@ fn run_charge_for_dirty_stable64_test() {
+ csg
+ cc * 15
+ cs * 2
+ cd * 3
+ cd
+ csw * 2
+ csr
+ cl
+ cg
+ overhead
+ overhead * cd
);

// Now run the same with insufficient instructions
Expand Down Expand Up @@ -1170,7 +1165,8 @@ fn metering_wasm64_load_store_canister() {
(memory i64 1000)
)"#;

let embedder_config = EmbeddersConfig::default();
let mut embedder_config = EmbeddersConfig::default();
// embedder_config.dirty_page_overhead = NumInstructions::new(1);

let mut instance = WasmtimeInstanceBuilder::new()
.with_config(embedder_config)
Expand Down Expand Up @@ -1224,6 +1220,7 @@ fn metering_wasm64_load_store_canister() {
// Both stores hit Wasm page 0 (bytes 0 and 4096 are within the 64KB page),
// so only one heap page-first-write event occurs.
let overhead = deterministic_tracker_overhead(1, 0);
println!("overhead {}", overhead);
let total_cost =
1 + 2 * const_0 + const_17 + const_117 + const_4096 + 2 * store + load + drop + overhead;
assert_eq!(instr_used_wasm64, total_cost);
Expand Down
4 changes: 3 additions & 1 deletion rs/embedders/tests/wasmtime_embedder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3798,7 +3798,10 @@ fn run_wasm_and_get_instructions_used(
wat: &str,
use_deterministic_tracker: bool,
) -> NumInstructions {
let mut config = Config::default();
config.dirty_page_overhead = NumInstructions::new(1);
let mut instance = WasmtimeInstanceBuilder::new()
.with_config(config)
.with_deterministic_memory_tracker_enabled(use_deterministic_tracker)
.with_wat(wat)
.with_api_type(ApiType::update(
Expand Down Expand Up @@ -3830,7 +3833,6 @@ fn assert_deterministic_charges_extra(
) {
let prefetching_instructions = run_wasm_and_get_instructions_used(wat, false);
let deterministic_instructions = run_wasm_and_get_instructions_used(wat, true);

assert_eq!(
deterministic_instructions.get() - prefetching_instructions.get(),
expected_extra_instructions,
Expand Down
43 changes: 21 additions & 22 deletions rs/embedders/tests/wasmtime_random_memory_writes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ic_config::{
embedders::Config as EmbeddersConfig, execution_environment::Config as HypervisorConfig,
subnet_config::SchedulerConfig,
embedders::Config as EmbeddersConfig,
execution_environment::Config as HypervisorConfig,
subnet_config::{DEFAULT_DIRTY_PAGE_OVERHEAD, SchedulerConfig},
};
use ic_cycles_account_manager::{CyclesAccountManagerSubnetConfig, ResourceSaturation};
use ic_embedders::{
Expand Down Expand Up @@ -58,7 +59,7 @@ fn dsm_charge_per_wasm_page() -> u64 {
.deterministic_memory_tracker
== FlagStatus::Enabled
{
OS_PAGES_PER_WASM_PAGE as u64
OS_PAGES_PER_WASM_PAGE as u64 * DEFAULT_DIRTY_PAGE_OVERHEAD.get()
} else {
0
}
Expand Down Expand Up @@ -763,7 +764,7 @@ mod tests {

// Set maximum number of instructions to some low value to trap
// Note: system API calls get charged per call, see system_api::charges
let max_num_instructions = NumInstructions::new(10_000);
let max_num_instructions = NumInstructions::new(200_000);

// Consumes less than max_num_instructions.
let instructions_consumed_without_data = get_num_instructions_consumed(
Expand Down Expand Up @@ -924,9 +925,7 @@ mod tests {
+ ic_embedders::wasmtime_embedder::system_api_complexity::overhead::STABLE_WRITE
.get()
+ STABLE_OP_BYTES
+ SchedulerConfig::application_subnet()
.dirty_page_overhead
.get()
+ dsm_charge_per_wasm_page()
+ dsm_charge_per_wasm_page() + dsm_charge_per_wasm_page()
);
}
Expand All @@ -949,7 +948,7 @@ mod tests {
+ ic_embedders::wasmtime_embedder::system_api_complexity::overhead::STABLE_WRITE
.get()
+ STABLE_OP_BYTES
+ SchedulerConfig::system_subnet().dirty_page_overhead.get()
+ dsm_charge_per_wasm_page()
+ dsm_charge_per_wasm_page() + dsm_charge_per_wasm_page()
);
}
Expand All @@ -973,9 +972,7 @@ mod tests {
+ ic_embedders::wasmtime_embedder::system_api_complexity::overhead::STABLE_WRITE
.get()
+ STABLE_OP_BYTES
+ SchedulerConfig::application_subnet()
.dirty_page_overhead
.get()
+ dsm_charge_per_wasm_page()
+ dsm_charge_per_wasm_page() + dsm_charge_per_wasm_page()
);
}
Expand All @@ -998,7 +995,7 @@ mod tests {
+ ic_embedders::wasmtime_embedder::system_api_complexity::overhead::STABLE_WRITE
.get()
+ STABLE_OP_BYTES
+ SchedulerConfig::system_subnet().dirty_page_overhead.get()
+ dsm_charge_per_wasm_page()
+ dsm_charge_per_wasm_page() + dsm_charge_per_wasm_page()
);
}
Expand Down Expand Up @@ -1075,12 +1072,13 @@ mod tests {
let dirty_heap = run_stats.wasm_dirty_pages.len() as u64;
let consumed_instructions =
consumed_instructions - instructions_consumed_without_data;
let incremental_tracker =
tracker_charge(&instance_stats).saturating_sub(dry_run_tracker);
let incremental_dirty =
dirty_heap.saturating_sub(dry_run_dirty_heap) * dirty_heap_cost;
assert_eq!(
(consumed_instructions.get()
- dirty_heap * dirty_heap_cost
- tracker_charge(&instance_stats)) as usize,
(payload_size / BYTES_PER_INSTRUCTION)
- (dry_run_dirty_heap * dirty_heap_cost + dry_run_tracker) as usize,
consumed_instructions.get() - incremental_dirty - incremental_tracker,
payload_size as u64 / BYTES_PER_INSTRUCTION as u64,
);
}

Expand All @@ -1097,13 +1095,14 @@ mod tests {
let dirty_heap = run_stats.wasm_dirty_pages.len() as u64;
let consumed_instructions =
consumed_instructions - instructions_consumed_without_data;
let incremental_tracker =
tracker_charge(&instance_stats).saturating_sub(dry_run_tracker);
let incremental_dirty =
dirty_heap.saturating_sub(dry_run_dirty_heap) * dirty_heap_cost;

assert_eq!(
(consumed_instructions.get()
- dirty_heap * dirty_heap_cost
- tracker_charge(&instance_stats)) as usize,
(2 * payload_size / BYTES_PER_INSTRUCTION)
- (dry_run_dirty_heap * dirty_heap_cost + dry_run_tracker) as usize
consumed_instructions.get() - incremental_dirty - incremental_tracker,
2 * payload_size as u64 / BYTES_PER_INSTRUCTION as u64,
);
}
})
Expand Down
Loading
Loading