Skip to content

Commit

Permalink
feat(wasmtime) new 'cache_config' directive for compilation cache
Browse files Browse the repository at this point in the history
This adds support for `wasmtime { cache_config <config.toml>; }`, which
enables disk caching of ahead-of-time compilation of `.wasm` files.

This should alleviate noticeable CPU spikes when starting up workers using
Wasmtime and Wasm modules larger than a few megabytes.

Signed-off-by: Thibault Charbonnier <[email protected]>
  • Loading branch information
hishamhm authored and thibaultcha committed Apr 24, 2024
1 parent 4ed3817 commit 91d447f
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 2 deletions.
19 changes: 19 additions & 0 deletions docs/DIRECTIVES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
By alphabetical order:

- [backtraces](#backtraces)
- [cache_config](#cache-config)
- [compiler](#compiler)
- [flag](#flag)
- [module](#module)
Expand Down Expand Up @@ -57,6 +58,7 @@ By context:
- [tls_verify_cert](#tls_verify_cert)
- [tls_verify_host](#tls_verify_host)
- `wasmtime{}`
- [cache_config](#cache-config)
- [flag](#flag)
- `wasmer{}`
- [flag](#flag)
Expand Down Expand Up @@ -131,6 +133,23 @@ Different runtimes support different compilers:

[Back to TOC](#directives)

cache_config
------------

**usage** | `cache_config <path>;`
------------:|:----------------------------------------------------------------
**contexts** | `wasmtime{}`
**default** |
**example** | `cache_config /path/to/wasmtime_config.toml;`

Enables Wasmtime's compilation cache and loads the specified configuration file.

By default the Wasmtime compilation cache is disabled. If specified, the path
must point to a file on the filesystem with TOML configuration; see
https://bytecodealliance.github.io/wasmtime/cli-cache.html.

[Back to TOC](#directives)

flag
----

Expand Down
8 changes: 8 additions & 0 deletions src/wasm/ngx_wasm_core_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ static ngx_command_t ngx_wasm_core_commands[] = {
0,
NULL },

{ ngx_string("cache_config"),
NGX_WASMTIME_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_WA_WASM_CONF_OFFSET,
offsetof(ngx_wasm_core_conf_t, vm_conf)
+ offsetof(ngx_wavm_conf_t, cache_config),
NULL },

{ ngx_string("compiler"),
NGX_WASM_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
Expand Down
1 change: 1 addition & 0 deletions src/wasm/wrt/ngx_wrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef struct ngx_wavm_instance_s ngx_wavm_instance_t;
typedef struct {
const ngx_str_t *vm_name;
const ngx_str_t *runtime_name;
ngx_str_t cache_config;
ngx_str_t compiler;
ngx_flag_t backtraces;
ngx_array_t flags;
Expand Down
43 changes: 41 additions & 2 deletions src/wasm/wrt/ngx_wrt_wasmtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ typedef void (*wasmtime_config_set_int_pt)(wasm_config_t *config,
typedef void (*wasmtime_config_set_bool_pt)(wasm_config_t *config, bool value);


static u_char *ngx_wasmtime_log_handler(ngx_wrt_res_t *res, u_char *buf,
size_t len);


static ngx_int_t
size_flag_handler(wasm_config_t *config, ngx_str_t *name, ngx_str_t *value,
ngx_log_t *log, void *wrt_setter)
Expand Down Expand Up @@ -129,10 +133,12 @@ profiler_flag_handler(wasm_config_t *config, ngx_str_t *name, ngx_str_t *value,
static wasm_config_t *
ngx_wasmtime_init_conf(ngx_wavm_conf_t *conf, ngx_log_t *log)
{
wasm_config_t *config;
char *pathname;
u_char *errmsg;
wasm_config_t *config;
wasmtime_error_t *err;
#if 0
wasm_name_t msg;
wasmtime_error_t *err = NULL;
#endif

ngx_wa_assert(conf->backtraces != NGX_CONF_UNSET);
Expand Down Expand Up @@ -160,6 +166,39 @@ ngx_wasmtime_init_conf(ngx_wavm_conf_t *conf, ngx_log_t *log)
wasmtime_config_static_memory_maximum_size_set(config, 0);
#endif

if (conf->cache_config.len) {
ngx_wavm_log_error(NGX_LOG_INFO, log, NULL,
"setting wasmtime cache config file: \"%V\"",
&conf->cache_config);

pathname = ngx_calloc(conf->cache_config.len + 1, log);
if (pathname == NULL) {
goto error;
}

ngx_memcpy(pathname, conf->cache_config.data, conf->cache_config.len);

err = wasmtime_config_cache_config_load(config, pathname);

ngx_free(pathname);

if (err) {
errmsg = ngx_calloc(NGX_MAX_ERROR_STR + 1, log);
if (errmsg == NULL) {
goto error;
}

ngx_wasmtime_log_handler((ngx_wrt_res_t *) err, errmsg,
NGX_MAX_ERROR_STR);

ngx_log_error(NGX_LOG_EMERG, log, 0,
"failed configuring wasmtime cache; %s",
errmsg);

goto error;
}
}

if (conf->compiler.len) {
if (ngx_str_eq(conf->compiler.data, conf->compiler.len,
"auto", -1))
Expand Down
114 changes: 114 additions & 0 deletions t/01-wasm/directives/011-wasmtime_cache_config_directive.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker:

use strict;
use lib '.';
use t::TestWasmX;

if ($t::TestWasmX::nginxV !~ m/wasmtime/) {
plan(skip_all => "not built with Wasmtime, skipping");

} else {
plan_tests(4);
}

run_tests();

__DATA__

=== TEST 1: wasmtime cache_config - missing file
--- main_config
wasm {
wasmtime {
cache_config missing_file;
}
}
--- error_log eval
qr/\[emerg\] .*? failed configuring wasmtime cache; failed to read config file: missing_file/
--- no_error_log
[error]
[crit]
--- must_die



=== TEST 2: wasmtime cache_config - invalid contents file
--- user_files
>>> wasmtime_config.toml
invalid contents
--- main_config
wasm {
wasmtime {
cache_config $TEST_NGINX_HTML_DIR/wasmtime_config.toml;
}
}
--- error_log eval
qr@\[emerg\] .*? failed configuring wasmtime cache; failed to parse config file: .*/wasmtime_config.toml@
--- no_error_log
[error]
[crit]
--- must_die



=== TEST 3: wasmtime cache_config - valid file, cache disabled
--- user_files
>>> wasmtime_config.toml
[cache]
enabled = false
--- main_config eval
qq{
wasm {
module hostcalls $t::TestWasmX::crates/hostcalls.wasm;

wasmtime {
cache_config $ENV{TEST_NGINX_HTML_DIR}/wasmtime_config.toml;
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header \
value=Hello:wasm';
proxy_wasm hostcalls 'test=/t/echo/headers';
}
--- response_body
Host: localhost
Connection: close
Hello: wasm
--- error_log eval
qr@setting wasmtime cache config file: ".*/wasmtime_config.toml"@
--- no_error_log
[error]



=== TEST 4: wasmtime cache_config - valid file, cache enabled
--- user_files
>>> wasmtime_config.toml
[cache]
enabled = true
directory = "/tmp/ngx_wasm_module/cache/wasmtime"
--- main_config eval
qq{
wasm {
module hostcalls $t::TestWasmX::crates/hostcalls.wasm;

wasmtime {
cache_config $ENV{TEST_NGINX_HTML_DIR}/wasmtime_config.toml;
}
}
}
--- config
location /t {
proxy_wasm hostcalls 'test=/t/set_request_header \
value=Hello:wasm';
proxy_wasm hostcalls 'test=/t/echo/headers';
}
--- response_body
Host: localhost
Connection: close
Hello: wasm
--- error_log eval
qr@setting wasmtime cache config file: ".*/wasmtime_config.toml"@
--- no_error_log
[error]

0 comments on commit 91d447f

Please sign in to comment.