1 //! Generate instance limits for the pooling allocation strategy. 2 3 use arbitrary::{Arbitrary, Unstructured}; 4 use wasmtime::MpkEnabled; 5 6 /// Configuration for `wasmtime::PoolingAllocationStrategy`. 7 #[derive(Debug, Clone, Eq, PartialEq, Hash)] 8 #[expect(missing_docs, reason = "self-describing field names")] 9 pub struct PoolingAllocationConfig { 10 pub total_component_instances: u32, 11 pub total_core_instances: u32, 12 pub total_memories: u32, 13 pub total_tables: u32, 14 pub total_stacks: u32, 15 16 pub max_memory_size: usize, 17 pub table_elements: usize, 18 19 pub component_instance_size: usize, 20 pub max_memories_per_component: u32, 21 pub max_tables_per_component: u32, 22 23 pub core_instance_size: usize, 24 pub max_memories_per_module: u32, 25 pub max_tables_per_module: u32, 26 27 pub table_keep_resident: usize, 28 pub linear_memory_keep_resident: usize, 29 30 pub decommit_batch_size: usize, 31 pub max_unused_warm_slots: u32, 32 33 pub async_stack_keep_resident: usize, 34 35 pub memory_protection_keys: MpkEnabled, 36 pub max_memory_protection_keys: usize, 37 } 38 39 impl PoolingAllocationConfig { 40 /// Convert the generated limits to Wasmtime limits. 41 pub fn configure(&self, cfg: &mut wasmtime_cli_flags::CommonOptions) { 42 cfg.opts.pooling_total_component_instances = Some(self.total_component_instances); 43 cfg.opts.pooling_total_core_instances = Some(self.total_core_instances); 44 cfg.opts.pooling_total_memories = Some(self.total_memories); 45 cfg.opts.pooling_total_tables = Some(self.total_tables); 46 cfg.opts.pooling_total_stacks = Some(self.total_stacks); 47 48 cfg.opts.pooling_max_memory_size = Some(self.max_memory_size); 49 cfg.opts.pooling_table_elements = Some(self.table_elements); 50 51 cfg.opts.pooling_max_component_instance_size = Some(self.component_instance_size); 52 cfg.opts.pooling_max_memories_per_component = Some(self.max_memories_per_component); 53 cfg.opts.pooling_max_tables_per_component = Some(self.max_tables_per_component); 54 55 cfg.opts.pooling_max_core_instance_size = Some(self.core_instance_size); 56 cfg.opts.pooling_max_memories_per_module = Some(self.max_memories_per_module); 57 cfg.opts.pooling_max_tables_per_module = Some(self.max_tables_per_module); 58 59 cfg.opts.pooling_table_keep_resident = Some(self.table_keep_resident); 60 cfg.opts.pooling_memory_keep_resident = Some(self.linear_memory_keep_resident); 61 62 cfg.opts.pooling_decommit_batch_size = Some(self.decommit_batch_size); 63 cfg.opts.pooling_max_unused_warm_slots = Some(self.max_unused_warm_slots); 64 65 cfg.opts.pooling_async_stack_keep_resident = Some(self.async_stack_keep_resident); 66 67 cfg.opts.pooling_memory_protection_keys = Some(self.memory_protection_keys); 68 cfg.opts.pooling_max_memory_protection_keys = Some(self.max_memory_protection_keys); 69 } 70 } 71 72 impl<'a> Arbitrary<'a> for PoolingAllocationConfig { 73 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 74 const MAX_COUNT: u32 = 100; 75 const MAX_TABLES: u32 = 100; 76 const MAX_MEMORIES: u32 = 100; 77 const MAX_ELEMENTS: usize = 1000; 78 const MAX_MEMORY_SIZE: usize = 10 * (1 << 20); // 10 MiB 79 const MAX_SIZE: usize = 1 << 20; // 1 MiB 80 const MAX_INSTANCE_MEMORIES: u32 = 10; 81 const MAX_INSTANCE_TABLES: u32 = 10; 82 83 let total_memories = u.int_in_range(1..=MAX_MEMORIES)?; 84 85 Ok(Self { 86 total_component_instances: u.int_in_range(1..=MAX_COUNT)?, 87 total_core_instances: u.int_in_range(1..=MAX_COUNT)?, 88 total_memories, 89 total_tables: u.int_in_range(1..=MAX_TABLES)?, 90 total_stacks: u.int_in_range(1..=MAX_COUNT)?, 91 92 max_memory_size: u.int_in_range(0..=MAX_MEMORY_SIZE)?, 93 table_elements: u.int_in_range(0..=MAX_ELEMENTS)?, 94 95 component_instance_size: u.int_in_range(0..=MAX_SIZE)?, 96 max_memories_per_component: u.int_in_range(1..=MAX_INSTANCE_MEMORIES)?, 97 max_tables_per_component: u.int_in_range(1..=MAX_INSTANCE_TABLES)?, 98 99 core_instance_size: u.int_in_range(0..=MAX_SIZE)?, 100 max_memories_per_module: u.int_in_range(1..=MAX_INSTANCE_MEMORIES)?, 101 max_tables_per_module: u.int_in_range(1..=MAX_INSTANCE_TABLES)?, 102 103 table_keep_resident: u.int_in_range(0..=1 << 20)?, 104 linear_memory_keep_resident: u.int_in_range(0..=1 << 20)?, 105 106 decommit_batch_size: u.int_in_range(1..=1000)?, 107 max_unused_warm_slots: u.int_in_range(0..=total_memories + 10)?, 108 109 async_stack_keep_resident: u.int_in_range(0..=1 << 20)?, 110 111 memory_protection_keys: *u.choose(&[MpkEnabled::Auto, MpkEnabled::Disable])?, 112 max_memory_protection_keys: u.int_in_range(1..=20)?, 113 }) 114 } 115 } 116