@@ -82,6 +82,10 @@ impl Default for Config {
82
82
inner. native_unwind_info ( false ) ;
83
83
84
84
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
+
85
89
// By default enable the pooling instance allocator in Wasmtime. This
86
90
// drastically reduces syscall/kernel overhead for wasm execution,
87
91
// especially in async contexts where async stacks must be allocated.
@@ -92,23 +96,71 @@ impl Default for Config {
92
96
// supported though as an escape valve for if this is a problem.
93
97
let mut pooling_config = PoolingAllocationConfig :: default ( ) ;
94
98
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 ) )
96
133
// This number accounts for internal data structures that Wasmtime allocates for each instance.
97
134
// Instance allocation is proportional to the number of "things" in a wasm module like functions,
98
135
// globals, memories, etc. Instance allocations are relatively small and are largely inconsequential
99
136
// compared to other runtime state, but a number needs to be chosen here so a relatively large threshold
100
137
// of 10MB is arbitrarily chosen. It should be unlikely that any reasonably-sized module hits this limit.
101
138
. max_component_instance_size ( env ( "SPIN_WASMTIME_INSTANCE_SIZE" , 10 * MB ) as usize )
102
139
. 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.
103
156
. 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 ) )
109
158
. 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 ) )
112
164
// Nothing is lost from allowing the maximum size of memory for
113
165
// all instance as it's still limited through other the normal
114
166
// `StoreLimitsAsync` accounting method too.
0 commit comments