1becdee57SLann use core::sync::atomic::Ordering;
2becdee57SLann 
3becdee57SLann use crate::{Engine, vm::PoolingInstanceAllocator};
4becdee57SLann 
5becdee57SLann /// `PoolingAllocatorMetrics` provides access to runtime metrics of a pooling
6becdee57SLann /// allocator configured with [`crate::InstanceAllocationStrategy::Pooling`].
7becdee57SLann ///
8becdee57SLann /// This is a cheap cloneable handle which can be obtained with
9becdee57SLann /// [`Engine::pooling_allocator_metrics`].
10becdee57SLann #[derive(Clone)]
11becdee57SLann pub struct PoolingAllocatorMetrics {
12becdee57SLann     engine: Engine,
13becdee57SLann }
14becdee57SLann 
15becdee57SLann impl PoolingAllocatorMetrics {
new(engine: &Engine) -> Option<Self>16becdee57SLann     pub(crate) fn new(engine: &Engine) -> Option<Self> {
17becdee57SLann         engine.allocator().as_pooling().map(|_| Self {
18becdee57SLann             engine: engine.clone(),
19becdee57SLann         })
20becdee57SLann     }
21becdee57SLann 
22becdee57SLann     /// Returns the number of core (module) instances currently allocated.
core_instances(&self) -> u6423becdee57SLann     pub fn core_instances(&self) -> u64 {
24becdee57SLann         self.allocator().live_core_instances.load(Ordering::Relaxed)
25becdee57SLann     }
26becdee57SLann 
27becdee57SLann     /// Returns the number of component instances currently allocated.
component_instances(&self) -> u6428becdee57SLann     pub fn component_instances(&self) -> u64 {
29becdee57SLann         self.allocator()
30becdee57SLann             .live_component_instances
31becdee57SLann             .load(Ordering::Relaxed)
32becdee57SLann     }
33becdee57SLann 
34becdee57SLann     /// Returns the number of WebAssembly memories currently allocated.
memories(&self) -> usize35becdee57SLann     pub fn memories(&self) -> usize {
36becdee57SLann         self.allocator().live_memories.load(Ordering::Relaxed)
37becdee57SLann     }
38becdee57SLann 
39becdee57SLann     /// Returns the number of WebAssembly tables currently allocated.
tables(&self) -> usize40becdee57SLann     pub fn tables(&self) -> usize {
41becdee57SLann         self.allocator().live_tables.load(Ordering::Relaxed)
42becdee57SLann     }
43becdee57SLann 
44*c33c8b8dSAlex Crichton     /// Returns the number of WebAssembly stacks currently allocated.
45*c33c8b8dSAlex Crichton     #[cfg(feature = "async")]
stacks(&self) -> usize46*c33c8b8dSAlex Crichton     pub fn stacks(&self) -> usize {
47*c33c8b8dSAlex Crichton         self.allocator().live_stacks.load(Ordering::Relaxed)
48*c33c8b8dSAlex Crichton     }
49*c33c8b8dSAlex Crichton 
50*c33c8b8dSAlex Crichton     /// Returns the number of WebAssembly GC heaps currently allocated.
51*c33c8b8dSAlex Crichton     #[cfg(feature = "gc")]
gc_heaps(&self) -> usize52*c33c8b8dSAlex Crichton     pub fn gc_heaps(&self) -> usize {
53*c33c8b8dSAlex Crichton         self.allocator().live_gc_heaps.load(Ordering::Relaxed)
54*c33c8b8dSAlex Crichton     }
55*c33c8b8dSAlex Crichton 
56*c33c8b8dSAlex Crichton     /// Returns the number of slots for linear memories in this allocator which
57*c33c8b8dSAlex Crichton     /// are not currently in use but were previously used.
58*c33c8b8dSAlex Crichton     ///
59*c33c8b8dSAlex Crichton     /// A "warm" slot means that there was a previous instantiation of a memory
60*c33c8b8dSAlex Crichton     /// in that slot. Warm slots are favored in general for allocating new
61*c33c8b8dSAlex Crichton     /// memories over using a slot that has never been used before.
unused_warm_memories(&self) -> u3262*c33c8b8dSAlex Crichton     pub fn unused_warm_memories(&self) -> u32 {
63*c33c8b8dSAlex Crichton         self.allocator().memories.unused_warm_slots()
64*c33c8b8dSAlex Crichton     }
65*c33c8b8dSAlex Crichton 
66*c33c8b8dSAlex Crichton     /// Returns the number of bytes in this pooling allocator which are not part
67*c33c8b8dSAlex Crichton     /// of any in-used linear memory slot but were previously used and are kept
68*c33c8b8dSAlex Crichton     /// resident via the `*_keep_resident` configuration options.
unused_memory_bytes_resident(&self) -> usize69*c33c8b8dSAlex Crichton     pub fn unused_memory_bytes_resident(&self) -> usize {
70*c33c8b8dSAlex Crichton         self.allocator().memories.unused_bytes_resident()
71*c33c8b8dSAlex Crichton     }
72*c33c8b8dSAlex Crichton 
73*c33c8b8dSAlex Crichton     /// Returns the number of slots for tables in this allocator which are not
74*c33c8b8dSAlex Crichton     /// currently in use but were previously used.
75*c33c8b8dSAlex Crichton     ///
76*c33c8b8dSAlex Crichton     /// A "warm" slot means that there was a previous instantiation of a table
77*c33c8b8dSAlex Crichton     /// in that slot. Warm slots are favored in general for allocating new
78*c33c8b8dSAlex Crichton     /// tables over using a slot that has never been used before.
unused_warm_tables(&self) -> u3279*c33c8b8dSAlex Crichton     pub fn unused_warm_tables(&self) -> u32 {
80*c33c8b8dSAlex Crichton         self.allocator().tables.unused_warm_slots()
81*c33c8b8dSAlex Crichton     }
82*c33c8b8dSAlex Crichton 
83*c33c8b8dSAlex Crichton     /// Returns the number of bytes in this pooling allocator which are not part
84*c33c8b8dSAlex Crichton     /// of any in-used linear table slot but were previously used and are kept
85*c33c8b8dSAlex Crichton     /// resident via the `*_keep_resident` configuration options.
unused_table_bytes_resident(&self) -> usize86*c33c8b8dSAlex Crichton     pub fn unused_table_bytes_resident(&self) -> usize {
87*c33c8b8dSAlex Crichton         self.allocator().tables.unused_bytes_resident()
88*c33c8b8dSAlex Crichton     }
89*c33c8b8dSAlex Crichton 
90*c33c8b8dSAlex Crichton     /// Returns the number of slots for stacks in this allocator which are not
91*c33c8b8dSAlex Crichton     /// currently in use but were previously used.
92*c33c8b8dSAlex Crichton     ///
93*c33c8b8dSAlex Crichton     /// A "warm" slot means that there was a previous use of a stack
94*c33c8b8dSAlex Crichton     /// in that slot. Warm slots are favored in general for allocating new
95*c33c8b8dSAlex Crichton     /// stacks over using a slot that has never been used before.
96*c33c8b8dSAlex Crichton     #[cfg(feature = "async")]
unused_warm_stacks(&self) -> u3297*c33c8b8dSAlex Crichton     pub fn unused_warm_stacks(&self) -> u32 {
98*c33c8b8dSAlex Crichton         self.allocator().stacks.unused_warm_slots()
99*c33c8b8dSAlex Crichton     }
100*c33c8b8dSAlex Crichton 
101*c33c8b8dSAlex Crichton     /// Returns the number of bytes in this pooling allocator which are not part
102*c33c8b8dSAlex Crichton     /// of any in-used linear stack slot but were previously used and are kept
103*c33c8b8dSAlex Crichton     /// resident via the `*_keep_resident` configuration options.
104*c33c8b8dSAlex Crichton     ///
105*c33c8b8dSAlex Crichton     /// This returns `None` if the `async_stack_zeroing` option is disabled or
106*c33c8b8dSAlex Crichton     /// if the platform doesn't manage stacks (e.g. Windows returns `None`).
107*c33c8b8dSAlex Crichton     #[cfg(feature = "async")]
unused_stack_bytes_resident(&self) -> Option<usize>108*c33c8b8dSAlex Crichton     pub fn unused_stack_bytes_resident(&self) -> Option<usize> {
109*c33c8b8dSAlex Crichton         self.allocator().stacks.unused_bytes_resident()
110*c33c8b8dSAlex Crichton     }
111*c33c8b8dSAlex Crichton 
allocator(&self) -> &PoolingInstanceAllocator112becdee57SLann     fn allocator(&self) -> &PoolingInstanceAllocator {
113becdee57SLann         self.engine
114becdee57SLann             .allocator()
115becdee57SLann             .as_pooling()
116becdee57SLann             .expect("engine should have pooling allocator")
117becdee57SLann     }
118becdee57SLann }
119becdee57SLann 
120becdee57SLann #[cfg(test)]
121becdee57SLann mod tests {
122*c33c8b8dSAlex Crichton     use crate::vm::instance::allocator::pooling::StackPool;
123becdee57SLann     use crate::{
124*c33c8b8dSAlex Crichton         Config, Enabled, InstanceAllocationStrategy, Module, PoolingAllocationConfig, Result,
125*c33c8b8dSAlex Crichton         Store,
126becdee57SLann         component::{Component, Linker},
127becdee57SLann     };
128*c33c8b8dSAlex Crichton     use std::vec::Vec;
129becdee57SLann 
130becdee57SLann     use super::*;
131becdee57SLann 
132becdee57SLann     // A component with 1 core instance, 1 memory, 1 table
133becdee57SLann     const TEST_COMPONENT: &[u8] = b"
134becdee57SLann         (component
135becdee57SLann             (core module $m
136becdee57SLann                 (memory 1)
137becdee57SLann                 (table 1 funcref)
138becdee57SLann             )
139becdee57SLann             (core instance (instantiate (module $m)))
140becdee57SLann         )
141becdee57SLann     ";
142becdee57SLann 
small_pool_config() -> PoolingAllocationConfig143*c33c8b8dSAlex Crichton     pub(crate) fn small_pool_config() -> PoolingAllocationConfig {
144*c33c8b8dSAlex Crichton         let mut config = PoolingAllocationConfig::new();
145*c33c8b8dSAlex Crichton 
146*c33c8b8dSAlex Crichton         config.total_memories(10);
147*c33c8b8dSAlex Crichton         config.max_memory_size(2 << 16);
148*c33c8b8dSAlex Crichton         config.total_tables(10);
149*c33c8b8dSAlex Crichton         config.table_elements(10);
150*c33c8b8dSAlex Crichton         config.total_stacks(1);
151*c33c8b8dSAlex Crichton 
152*c33c8b8dSAlex Crichton         config
153*c33c8b8dSAlex Crichton     }
154*c33c8b8dSAlex Crichton 
155becdee57SLann     #[test]
156becdee57SLann     #[cfg_attr(miri, ignore)]
smoke_test()157becdee57SLann     fn smoke_test() {
158becdee57SLann         // Start with nothing
159*c33c8b8dSAlex Crichton         let engine = Engine::new(&Config::new().allocation_strategy(small_pool_config())).unwrap();
160becdee57SLann         let metrics = engine.pooling_allocator_metrics().unwrap();
161becdee57SLann 
162becdee57SLann         assert_eq!(metrics.core_instances(), 0);
163becdee57SLann         assert_eq!(metrics.component_instances(), 0);
164becdee57SLann         assert_eq!(metrics.memories(), 0);
165becdee57SLann         assert_eq!(metrics.tables(), 0);
166becdee57SLann 
167becdee57SLann         // Instantiate one of each
168becdee57SLann         let mut store = Store::new(&engine, ());
169becdee57SLann         let component = Component::new(&engine, TEST_COMPONENT).unwrap();
170becdee57SLann         let linker = Linker::new(&engine);
171becdee57SLann         let instance = linker.instantiate(&mut store, &component).unwrap();
172becdee57SLann 
173becdee57SLann         assert_eq!(metrics.core_instances(), 1);
174becdee57SLann         assert_eq!(metrics.component_instances(), 1);
175becdee57SLann         assert_eq!(metrics.memories(), 1);
176becdee57SLann         assert_eq!(metrics.tables(), 1);
177becdee57SLann 
178becdee57SLann         // Back to nothing
179becdee57SLann         let _ = (instance, store);
180becdee57SLann 
181becdee57SLann         assert_eq!(metrics.core_instances(), 0);
182becdee57SLann         assert_eq!(metrics.component_instances(), 0);
183becdee57SLann         assert_eq!(metrics.memories(), 0);
184becdee57SLann         assert_eq!(metrics.tables(), 0);
185becdee57SLann     }
186becdee57SLann 
187becdee57SLann     #[test]
test_non_pooling_allocator()188becdee57SLann     fn test_non_pooling_allocator() {
189becdee57SLann         let engine =
190becdee57SLann             Engine::new(&Config::new().allocation_strategy(InstanceAllocationStrategy::OnDemand))
191becdee57SLann                 .unwrap();
192becdee57SLann 
193becdee57SLann         let maybe_metrics = engine.pooling_allocator_metrics();
194becdee57SLann         assert!(maybe_metrics.is_none());
195becdee57SLann     }
196*c33c8b8dSAlex Crichton 
197*c33c8b8dSAlex Crichton     #[test]
198*c33c8b8dSAlex Crichton     #[cfg_attr(any(miri, not(target_os = "linux")), ignore)]
unused_memories_tables_and_more() -> Result<()>199*c33c8b8dSAlex Crichton     fn unused_memories_tables_and_more() -> Result<()> {
200*c33c8b8dSAlex Crichton         let mut pool = small_pool_config();
201*c33c8b8dSAlex Crichton         pool.linear_memory_keep_resident(65536);
202*c33c8b8dSAlex Crichton         pool.table_keep_resident(65536);
203*c33c8b8dSAlex Crichton         pool.pagemap_scan(Enabled::Auto);
204*c33c8b8dSAlex Crichton         let mut config = Config::new();
205*c33c8b8dSAlex Crichton         config.allocation_strategy(pool);
206*c33c8b8dSAlex Crichton         let engine = Engine::new(&config)?;
207*c33c8b8dSAlex Crichton 
208*c33c8b8dSAlex Crichton         let metrics = engine.pooling_allocator_metrics().unwrap();
209*c33c8b8dSAlex Crichton         let host_page_size = crate::vm::host_page_size();
210*c33c8b8dSAlex Crichton 
211*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 0);
212*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 0);
213*c33c8b8dSAlex Crichton         assert_eq!(metrics.component_instances(), 0);
214*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 0);
215*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 0);
216*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 0);
217*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_memory_bytes_resident(), 0);
218*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 0);
219*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_table_bytes_resident(), 0);
220*c33c8b8dSAlex Crichton 
221*c33c8b8dSAlex Crichton         let m1 = Module::new(
222*c33c8b8dSAlex Crichton             &engine,
223*c33c8b8dSAlex Crichton             r#"
224*c33c8b8dSAlex Crichton             (module (memory (export "m") 1) (table 1 funcref))
225*c33c8b8dSAlex Crichton         "#,
226*c33c8b8dSAlex Crichton         )?;
227*c33c8b8dSAlex Crichton 
228*c33c8b8dSAlex Crichton         let mut store = Store::new(&engine, ());
229*c33c8b8dSAlex Crichton         crate::Instance::new(&mut store, &m1, &[])?;
230*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 1);
231*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 1);
232*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 1);
233*c33c8b8dSAlex Crichton         assert_eq!(metrics.component_instances(), 0);
234*c33c8b8dSAlex Crichton         drop(store);
235*c33c8b8dSAlex Crichton 
236*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 0);
237*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 0);
238*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 0);
239*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 1);
240*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 1);
241*c33c8b8dSAlex Crichton         if PoolingAllocationConfig::is_pagemap_scan_available() {
242*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), 0);
243*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), host_page_size);
244*c33c8b8dSAlex Crichton         } else {
245*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), 65536);
246*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), host_page_size);
247*c33c8b8dSAlex Crichton         }
248*c33c8b8dSAlex Crichton 
249*c33c8b8dSAlex Crichton         let mut store = Store::new(&engine, ());
250*c33c8b8dSAlex Crichton         let i = crate::Instance::new(&mut store, &m1, &[])?;
251*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 1);
252*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 1);
253*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 1);
254*c33c8b8dSAlex Crichton         assert_eq!(metrics.component_instances(), 0);
255*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 0);
256*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 0);
257*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_memory_bytes_resident(), 0);
258*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_table_bytes_resident(), 0);
259*c33c8b8dSAlex Crichton         let m = i.get_memory(&mut store, "m").unwrap();
260*c33c8b8dSAlex Crichton         m.data_mut(&mut store)[0] = 1;
261*c33c8b8dSAlex Crichton         m.grow(&mut store, 1)?;
262*c33c8b8dSAlex Crichton         drop(store);
263*c33c8b8dSAlex Crichton 
264*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 0);
265*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 0);
266*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 0);
267*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 1);
268*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 1);
269*c33c8b8dSAlex Crichton         if PoolingAllocationConfig::is_pagemap_scan_available() {
270*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), host_page_size);
271*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), host_page_size);
272*c33c8b8dSAlex Crichton         } else {
273*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), 65536);
274*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), host_page_size);
275*c33c8b8dSAlex Crichton         }
276*c33c8b8dSAlex Crichton 
277*c33c8b8dSAlex Crichton         let stores = (0..10)
278*c33c8b8dSAlex Crichton             .map(|_| {
279*c33c8b8dSAlex Crichton                 let mut store = Store::new(&engine, ());
280*c33c8b8dSAlex Crichton                 crate::Instance::new(&mut store, &m1, &[]).unwrap();
281*c33c8b8dSAlex Crichton                 store
282*c33c8b8dSAlex Crichton             })
283*c33c8b8dSAlex Crichton             .collect::<Vec<_>>();
284*c33c8b8dSAlex Crichton 
285*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 10);
286*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 10);
287*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 10);
288*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 0);
289*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 0);
290*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_memory_bytes_resident(), 0);
291*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_table_bytes_resident(), 0);
292*c33c8b8dSAlex Crichton 
293*c33c8b8dSAlex Crichton         drop(stores);
294*c33c8b8dSAlex Crichton 
295*c33c8b8dSAlex Crichton         assert_eq!(metrics.memories(), 00);
296*c33c8b8dSAlex Crichton         assert_eq!(metrics.tables(), 00);
297*c33c8b8dSAlex Crichton         assert_eq!(metrics.core_instances(), 00);
298*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_memories(), 10);
299*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_tables(), 10);
300*c33c8b8dSAlex Crichton         if PoolingAllocationConfig::is_pagemap_scan_available() {
301*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), host_page_size);
302*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), 10 * host_page_size);
303*c33c8b8dSAlex Crichton         } else {
304*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_memory_bytes_resident(), 10 * 65536);
305*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_table_bytes_resident(), 10 * host_page_size);
306*c33c8b8dSAlex Crichton         }
307*c33c8b8dSAlex Crichton 
308*c33c8b8dSAlex Crichton         Ok(())
309*c33c8b8dSAlex Crichton     }
310*c33c8b8dSAlex Crichton 
311*c33c8b8dSAlex Crichton     #[test]
312*c33c8b8dSAlex Crichton     #[cfg_attr(miri, ignore)]
gc_heaps() -> Result<()>313*c33c8b8dSAlex Crichton     fn gc_heaps() -> Result<()> {
314*c33c8b8dSAlex Crichton         let pool = small_pool_config();
315*c33c8b8dSAlex Crichton         let mut config = Config::new();
316*c33c8b8dSAlex Crichton         config.allocation_strategy(pool);
317*c33c8b8dSAlex Crichton         let engine = Engine::new(&config)?;
318*c33c8b8dSAlex Crichton 
319*c33c8b8dSAlex Crichton         let metrics = engine.pooling_allocator_metrics().unwrap();
320*c33c8b8dSAlex Crichton 
321*c33c8b8dSAlex Crichton         assert_eq!(metrics.gc_heaps(), 0);
322*c33c8b8dSAlex Crichton         let mut store = Store::new(&engine, ());
323*c33c8b8dSAlex Crichton         crate::ExternRef::new(&mut store, ())?;
324*c33c8b8dSAlex Crichton         assert_eq!(metrics.gc_heaps(), 1);
325*c33c8b8dSAlex Crichton         drop(store);
326*c33c8b8dSAlex Crichton         assert_eq!(metrics.gc_heaps(), 0);
327*c33c8b8dSAlex Crichton 
328*c33c8b8dSAlex Crichton         Ok(())
329*c33c8b8dSAlex Crichton     }
330*c33c8b8dSAlex Crichton 
331*c33c8b8dSAlex Crichton     #[tokio::test]
332*c33c8b8dSAlex Crichton     #[cfg_attr(miri, ignore)]
stacks() -> Result<()>333*c33c8b8dSAlex Crichton     async fn stacks() -> Result<()> {
334*c33c8b8dSAlex Crichton         let pool = small_pool_config();
335*c33c8b8dSAlex Crichton         let mut config = Config::new();
336*c33c8b8dSAlex Crichton         config.allocation_strategy(pool);
337*c33c8b8dSAlex Crichton         let engine = Engine::new(&config)?;
338*c33c8b8dSAlex Crichton 
339*c33c8b8dSAlex Crichton         let metrics = engine.pooling_allocator_metrics().unwrap();
340*c33c8b8dSAlex Crichton 
341*c33c8b8dSAlex Crichton         assert_eq!(metrics.stacks(), 0);
342*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_warm_stacks(), 0);
343*c33c8b8dSAlex Crichton         let mut store = Store::new(&engine, ());
344*c33c8b8dSAlex Crichton 
345*c33c8b8dSAlex Crichton         crate::Func::wrap(&mut store, || {})
346*c33c8b8dSAlex Crichton             .call_async(&mut store, &[], &mut [])
347*c33c8b8dSAlex Crichton             .await?;
348*c33c8b8dSAlex Crichton         assert_eq!(metrics.stacks(), 1);
349*c33c8b8dSAlex Crichton         drop(store);
350*c33c8b8dSAlex Crichton         assert_eq!(metrics.stacks(), 0);
351*c33c8b8dSAlex Crichton         assert_eq!(metrics.unused_stack_bytes_resident(), None);
352*c33c8b8dSAlex Crichton         if StackPool::enabled() {
353*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_warm_stacks(), 1);
354*c33c8b8dSAlex Crichton         } else {
355*c33c8b8dSAlex Crichton             assert_eq!(metrics.unused_warm_stacks(), 0);
356*c33c8b8dSAlex Crichton         }
357*c33c8b8dSAlex Crichton 
358*c33c8b8dSAlex Crichton         Ok(())
359*c33c8b8dSAlex Crichton     }
360becdee57SLann }
361