@@ -82,6 +82,10 @@ impl Default for Config {
8282 inner. native_unwind_info ( false ) ;
8383
8484 if use_pooling_allocator_by_default ( ) {
85+ // Baseline for the maximum number of instances in spin through
86+ // which a number of other defaults are derived below.
87+ let max_instances = env ( "SPIN_MAX_INSTANCE_COUNT" , 1_000 ) ;
88+
8589 // By default enable the pooling instance allocator in Wasmtime. This
8690 // drastically reduces syscall/kernel overhead for wasm execution,
8791 // especially in async contexts where async stacks must be allocated.
@@ -92,23 +96,71 @@ impl Default for Config {
9296 // supported though as an escape valve for if this is a problem.
9397 let mut pooling_config = PoolingAllocationConfig :: default ( ) ;
9498 pooling_config
95- . total_component_instances ( env ( "SPIN_WASMTIME_INSTANCE_COUNT" , 1_000 ) )
99+ // Configuration parameters which affect the total size of the
100+ // allocation pool as well as the maximum number of concurrently
101+ // live instances at once. These can be configured individually
102+ // but otherwise default to a factor-of-`max_instances` above.
103+ //
104+ // * Component instances are the maximum live number of
105+ // component instances or instantiations. In other words this
106+ // is the maximal concurrency that Spin can serve in terms of
107+ // HTTP rqeuests.
108+ //
109+ // * Memories mostly affect how big the virtual address space
110+ // reservation is for the pooling allocator. Memories require
111+ // ~4G of virtual address space meaning that we can run out
112+ // pretty quickly.
113+ //
114+ // * Tables are not as costly as memories in terms of virtual
115+ // memory and mostly just need to be in the same order of
116+ // magnitude to run that many components.
117+ //
118+ // * Core instances do not have a virtual memory reservation at
119+ // this time, it's just a counter to cap the maximum amount of
120+ // memory allocated (multiplied by `max_core_instance_size`
121+ // below) so the limit is more liberal.
122+ //
123+ // * Table elements limit the maximum size of any allocated
124+ // table, so it's set generously large. This does affect
125+ // virtual memory reservation but it's just 8 bytes per table
126+ // slot.
127+ . total_component_instances ( env ( "SPIN_WASMTIME_INSTANCE_COUNT" , max_instances) )
128+ . total_memories ( env ( "SPIN_WASMTIME_TOTAL_MEMORIES" , max_instances) )
129+ . total_tables ( env ( "SPIN_WASMTIME_TOTAL_TABLES" , 2 * max_instances) )
130+ . total_stacks ( env ( "SPIN_WASMTIME_TOTAL_STACKS" , max_instances) )
131+ . total_core_instances ( env ( "SPIN_WASMTIME_TOTAL_CORE_INSTANCES" , 4 * max_instances) )
132+ . table_elements ( env ( "SPIN_WASMTIME_INSTANCE_TABLE_ELEMENTS" , 100_000 ) )
96133 // This number accounts for internal data structures that Wasmtime allocates for each instance.
97134 // Instance allocation is proportional to the number of "things" in a wasm module like functions,
98135 // globals, memories, etc. Instance allocations are relatively small and are largely inconsequential
99136 // compared to other runtime state, but a number needs to be chosen here so a relatively large threshold
100137 // of 10MB is arbitrarily chosen. It should be unlikely that any reasonably-sized module hits this limit.
101138 . max_component_instance_size ( env ( "SPIN_WASMTIME_INSTANCE_SIZE" , 10 * MB ) as usize )
102139 . max_core_instance_size ( env ( "SPIN_WASMTIME_CORE_INSTANCE_SIZE" , 10 * MB ) as usize )
140+ // Configuration knobs for hard limits per-component for various
141+ // items that require allocations. Note that these are
142+ // per-component limits and instantiating a component still has
143+ // to fit into the `total_*` limits above at runtime.
144+ //
145+ // * Core instances are more or less a reflection of how many
146+ // nested components can be in a component (e.g. via
147+ // composition)
148+ // * The number of memories an instance can have effectively
149+ // limits the number of inner components a composed component
150+ // can have (since each inner component has its own memory).
151+ // We default to 32 for now, and we'll see how often this
152+ // limit gets reached.
153+ // * Tables here are roughly similar to memories but are set a
154+ // bit higher as it's more likely to have more tables than
155+ // memories in a component.
103156 . max_core_instances_per_component ( env ( "SPIN_WASMTIME_CORE_INSTANCE_COUNT" , 200 ) )
104- . max_tables_per_component ( env ( "SPIN_WASMTIME_INSTANCE_TABLES" , 20 ) )
105- . table_elements ( env ( "SPIN_WASMTIME_INSTANCE_TABLE_ELEMENTS" , 100_000 ) )
106- // The number of memories an instance can have effectively limits the number of inner components
107- // a composed component can have (since each inner component has its own memory). We default to 32 for now, and
108- // we'll see how often this limit gets reached.
157+ . max_tables_per_component ( env ( "SPIN_WASMTIME_INSTANCE_TABLES" , 64 ) )
109158 . max_memories_per_component ( env ( "SPIN_WASMTIME_INSTANCE_MEMORIES" , 32 ) )
110- . total_memories ( env ( "SPIN_WASMTIME_TOTAL_MEMORIES" , 1_000 ) )
111- . total_tables ( env ( "SPIN_WASMTIME_TOTAL_TABLES" , 2_000 ) )
159+ // Similar knobs as above, but as specified per-module instead
160+ // of per-component. Note that these limits are much lower as
161+ // core modules typically only have one of each.
162+ . max_tables_per_module ( env ( "SPIN_WASMTIME_MAX_TABLES_PER_MODULE" , 2 ) )
163+ . max_memories_per_module ( env ( "SPIN_WASMTIME_MAX_MEMORIES_PER_MODULE" , 2 ) )
112164 // Nothing is lost from allowing the maximum size of memory for
113165 // all instance as it's still limited through other the normal
114166 // `StoreLimitsAsync` accounting method too.
0 commit comments