Skip to content

Commit dc1d128

Browse files
authored
Respect pooling allocation options in wasmtime serve (bytecodealliance#8525)
* Respect pooling allocation options in `wasmtime serve` This commit updates the processing of pooling allocator options in `wasmtime serve`. Previously the pooling allocator was enabled by default but the options to configure it weren't processed due to how this default-enable was implemented. The option to enable it by default for `wasmtime serve`, but only `wasmtime serve`, is now processed differently in a way that handles various other pooling-allocator-related options. Closes bytecodealliance#8504 * Fix compile of bench api * Fix test build * Ignore newly added test as it's flaky
1 parent c48a8ce commit dc1d128

File tree

9 files changed

+79
-43
lines changed

9 files changed

+79
-43
lines changed

crates/bench-api/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ impl BenchState {
435435
execution_end: extern "C" fn(*mut u8),
436436
make_wasi_cx: impl FnMut() -> Result<WasiCtx> + 'static,
437437
) -> Result<Self> {
438-
let mut config = options.config(Some(&Triple::host().to_string()))?;
438+
let mut config = options.config(Some(&Triple::host().to_string()), None)?;
439439
// NB: always disable the compilation cache.
440440
config.disable_cache();
441441
let engine = Engine::new(&config)?;

crates/cli-flags/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,11 @@ impl CommonOptions {
432432
Ok(())
433433
}
434434

435-
pub fn config(&mut self, target: Option<&str>) -> Result<Config> {
435+
pub fn config(
436+
&mut self,
437+
target: Option<&str>,
438+
pooling_allocator_default: Option<bool>,
439+
) -> Result<Config> {
436440
self.configure();
437441
let mut config = Config::new();
438442

@@ -563,7 +567,7 @@ impl CommonOptions {
563567
}
564568

565569
match_feature! {
566-
["pooling-allocator" : self.opts.pooling_allocator]
570+
["pooling-allocator" : self.opts.pooling_allocator.or(pooling_allocator_default)]
567571
enable => {
568572
if enable {
569573
let mut cfg = wasmtime::PoolingAllocationConfig::default();

src/commands/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl CompileCommand {
6161
pub fn execute(mut self) -> Result<()> {
6262
self.common.init_logging()?;
6363

64-
let mut config = self.common.config(self.target.as_deref())?;
64+
let mut config = self.common.config(self.target.as_deref(), None)?;
6565

6666
if let Some(path) = self.emit_clif {
6767
if !path.exists() {

src/commands/explore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl ExploreCommand {
3030
pub fn execute(mut self) -> Result<()> {
3131
self.common.init_logging()?;
3232

33-
let config = self.common.config(self.target.as_deref())?;
33+
let config = self.common.config(self.target.as_deref(), None)?;
3434

3535
let bytes =
3636
Cow::Owned(std::fs::read(&self.module).with_context(|| {

src/commands/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl RunCommand {
7474
pub fn execute(mut self) -> Result<()> {
7575
self.run.common.init_logging()?;
7676

77-
let mut config = self.run.common.config(None)?;
77+
let mut config = self.run.common.config(None, None)?;
7878

7979
if self.run.common.wasm.timeout.is_some() {
8080
config.epoch_interruption(true);

src/commands/serve.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -247,23 +247,12 @@ impl ServeCommand {
247247
async fn serve(mut self) -> Result<()> {
248248
use hyper::server::conn::http1;
249249

250-
let mut config = self.run.common.config(None)?;
251-
match self.run.common.opts.pooling_allocator {
252-
// If explicitly enabled on the CLI then the pooling allocator was
253-
// already configured in the `config` method above. If the allocator
254-
// is explicitly disabled, then we don't want it. In both cases do
255-
// nothing.
256-
Some(true) | Some(false) => {}
257-
258-
// Otherwise though if not explicitly specified then always enable
259-
// the pooling allocator. The `wasmtime serve` use case is
260-
// tailor-made for pooling allocation and there's no downside to
261-
// enabling it.
262-
None => {
263-
let cfg = wasmtime::PoolingAllocationConfig::default();
264-
config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(cfg));
265-
}
266-
}
250+
// If not explicitly specified then always enable the pooling allocator.
251+
// The `wasmtime serve` use case is tailor-made for pooling allocation
252+
// and there's not much downside to enabling it.
253+
let pooling_allocator_default = Some(true);
254+
255+
let mut config = self.run.common.config(None, pooling_allocator_default)?;
267256
config.wasm_component_model(true);
268257
config.async_support(true);
269258

src/commands/wast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl WastCommand {
2323
pub fn execute(mut self) -> Result<()> {
2424
self.common.init_logging()?;
2525

26-
let config = self.common.config(None)?;
26+
let config = self.common.config(None, None)?;
2727
let store = Store::new(&Engine::new(&config)?, ());
2828
let mut wast_context = WastContext::new(store);
2929

tests/all/cli_tests.rs

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,36 +1640,51 @@ mod test_programs {
16401640
// all remaining output is left to be captured by future requests
16411641
// send to the server.
16421642
let mut line = String::new();
1643-
BufReader::new(child.stderr.as_mut().unwrap()).read_line(&mut line)?;
1644-
let addr_start = line.find("127.0.0.1").unwrap();
1645-
let addr = &line[addr_start..];
1646-
let addr_end = addr.find("/").unwrap();
1647-
let addr = &addr[..addr_end];
1648-
Ok(WasmtimeServe {
1649-
child: Some(child),
1650-
addr: addr.parse().unwrap(),
1651-
})
1643+
let mut reader = BufReader::new(child.stderr.take().unwrap());
1644+
reader.read_line(&mut line)?;
1645+
1646+
match line.find("127.0.0.1").and_then(|addr_start| {
1647+
let addr = &line[addr_start..];
1648+
let addr_end = addr.find("/")?;
1649+
addr[..addr_end].parse().ok()
1650+
}) {
1651+
Some(addr) => {
1652+
assert!(reader.buffer().is_empty());
1653+
child.stderr = Some(reader.into_inner());
1654+
Ok(WasmtimeServe {
1655+
child: Some(child),
1656+
addr,
1657+
})
1658+
}
1659+
None => {
1660+
child.kill()?;
1661+
child.wait()?;
1662+
reader.read_to_string(&mut line)?;
1663+
bail!("failed to start child: {line}")
1664+
}
1665+
}
16521666
}
16531667

16541668
/// Completes this server gracefully by printing the output on failure.
1655-
fn finish(mut self) -> Result<()> {
1669+
fn finish(mut self) -> Result<String> {
16561670
let mut child = self.child.take().unwrap();
16571671

16581672
// If the child process has already exited then collect the output
16591673
// and test if it succeeded. Otherwise it's still running so kill it
16601674
// and then reap it. Assume that if it's still running then the test
16611675
// has otherwise passed so no need to print the output.
1662-
if child.try_wait()?.is_some() {
1663-
let output = child.wait_with_output()?;
1664-
if output.status.success() {
1665-
return Ok(());
1666-
}
1667-
bail!("child failed {output:?}");
1676+
let known_failure = if child.try_wait()?.is_some() {
1677+
false
16681678
} else {
16691679
child.kill()?;
1670-
child.wait_with_output()?;
1680+
true
1681+
};
1682+
let output = child.wait_with_output()?;
1683+
if !known_failure && !output.status.success() {
1684+
bail!("child failed {output:?}");
16711685
}
1672-
Ok(())
1686+
1687+
Ok(String::from_utf8_lossy(&output.stderr).into_owned())
16731688
}
16741689

16751690
/// Send a request to this server and wait for the response.
@@ -1775,6 +1790,34 @@ mod test_programs {
17751790
server.finish()?;
17761791
Ok(())
17771792
}
1793+
1794+
#[tokio::test]
1795+
#[ignore] // TODO: printing stderr in the child and killing the child at the
1796+
// end of this test race so the stderr may be present or not. Need
1797+
// to implement a more graceful shutdown routine for `wasmtime
1798+
// serve`.
1799+
async fn cli_serve_respect_pooling_options() -> Result<()> {
1800+
let server = WasmtimeServe::new(CLI_SERVE_ECHO_ENV_COMPONENT, |cmd| {
1801+
cmd.arg("-Opooling-total-memories=0").arg("-Scli");
1802+
})?;
1803+
1804+
let result = server
1805+
.send_request(
1806+
hyper::Request::builder()
1807+
.uri("http://localhost/")
1808+
.header("env", "FOO")
1809+
.body(String::new())
1810+
.context("failed to make request")?,
1811+
)
1812+
.await;
1813+
assert!(result.is_err());
1814+
let stderr = server.finish()?;
1815+
assert!(
1816+
stderr.contains("maximum concurrent memory limit of 0 reached"),
1817+
"bad stderr: {stderr}",
1818+
);
1819+
Ok(())
1820+
}
17781821
}
17791822

17801823
#[test]

tests/disas.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl Test {
190190
// Use wasmtime::Config with its `emit_clif` option to get Wasmtime's
191191
// code generator to jettison CLIF out the back.
192192
let tempdir = TempDir::new().context("failed to make a tempdir")?;
193-
let mut config = self.opts.config(Some(&self.config.target))?;
193+
let mut config = self.opts.config(Some(&self.config.target), None)?;
194194
match self.config.test {
195195
TestKind::Clif | TestKind::Optimize => {
196196
config.emit_clif(tempdir.path());

0 commit comments

Comments
 (0)