Skip to content

Instantly share code, notes, and snippets.

@alexcrichton
Created September 9, 2021 15:44
Show Gist options
  • Save alexcrichton/e3ad76042c847981ab064e59325635aa to your computer and use it in GitHub Desktop.
Save alexcrichton/e3ad76042c847981ab064e59325635aa to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <wasmtime.h>
#define N 10000000
#ifdef WASM_H_API
static wasm_trap_t *host_i64(
const wasm_val_vec_t *args,
wasm_val_vec_t *results
) {
assert(results->size == 1);
results->data[0].of.i64 = 0;
results->data[0].kind = WASM_I64;
return NULL;
}
static wasm_trap_t *host_many(
const wasm_val_vec_t *args,
wasm_val_vec_t *results
) {
assert(args->size == 5);
assert(results->size == 1);
results->data[0].of.i32 = 0;
results->data[0].kind = WASM_I32;
return NULL;
}
#else
static wasm_trap_t *host_i64(
void *env,
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t nargs,
wasmtime_val_t *results,
size_t nresults
) {
assert(nresults == 1);
results[0].of.i64 = 0;
results[0].kind = WASM_I64;
return NULL;
}
static wasm_trap_t *host_many(
void *env,
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t nargs,
wasmtime_val_t *results,
size_t nresults
) {
assert(nargs == 5);
assert(nresults == 1);
results[0].of.i32 = 0;
results[0].kind = WASM_I32;
return NULL;
}
#endif
static void print_diff(const char *name, struct timespec *start, struct timespec *stop) {
struct timespec result;
if ((stop->tv_nsec - start->tv_nsec) < 0) {
result.tv_sec = stop->tv_sec - start->tv_sec - 1;
result.tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
} else {
result.tv_sec = stop->tv_sec - start->tv_sec;
result.tv_nsec = stop->tv_nsec - start->tv_nsec;
}
uint64_t nsec = ((uint64_t) result.tv_sec) * 1000000000 + (uint64_t) result.tv_nsec;
printf("%s - %ldns / iter\n", name, (long) (nsec / N));
}
int main() {
struct timespec start, stop;
int rc = 0;
wasm_engine_t *engine = wasm_engine_new();
const char *wat = "(module "
"(import \"\" \"i64\" (func $host (result i64))) "
"(import \"\" \"many\" (func $many (param i32 i32 i32 i32 i32) (result i32))) "
"(func (export \"nop\"))"
"(func (export \"i64\") (result i64) call $host)"
"(func (export \"many\") i32.const 0 i32.const 0 i32.const 0 i32.const 0 i32.const 0 call $many drop)"
")";
wasm_byte_vec_t wasm;
#ifdef OLD_WAT2WASM
wasm_byte_vec_t wat_bytes;
wat_bytes.data = (char*) wat;
wat_bytes.size = strlen(wat);
wasmtime_error_t *err = wasmtime_wat2wasm(&wat_bytes, &wasm);
#else
wasmtime_error_t *err = wasmtime_wat2wasm(wat, strlen(wat), &wasm);
#endif
assert(err == NULL);
#ifdef WASM_H_API
wasm_store_t *store = wasm_store_new(engine);
wasm_functype_t *ty = wasm_functype_new_0_1(wasm_valtype_new_i64());
wasm_func_t *i64 = wasm_func_new(store, ty, host_i64);
wasm_valtype_t *i32_t = wasm_valtype_new_i32();
wasm_valtype_t* many_params_p[5] = {i32_t, i32_t, i32_t, i32_t, i32_t};
wasm_valtype_t* many_results_p[1] = {i32_t};
wasm_valtype_vec_t many_params, many_results;
wasm_valtype_vec_new(&many_params, 5, many_params_p);
wasm_valtype_vec_new(&many_results, 1, many_results_p);
wasm_functype_t *many_ty = wasm_functype_new(&many_params, &many_results);
wasm_func_t *many = wasm_func_new(store, many_ty, host_many);
wasm_module_t *module = wasm_module_new(store, &wasm);
assert(module != NULL);
wasm_extern_t *imports_raw[2];
imports_raw[0] = wasm_func_as_extern(i64);
imports_raw[1] = wasm_func_as_extern(many);
wasm_extern_vec_t imports;
imports.size = 2;
imports.data = imports_raw;
wasm_trap_t *trap = NULL;
wasm_instance_t *instance = wasm_instance_new(store, module, &imports, &trap);
assert(trap == NULL);
assert(instance != NULL);
wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
assert(exports.size == 3);
wasm_func_t *nop_export = wasm_extern_as_func(exports.data[0]);
assert(nop_export != NULL);
wasm_func_t *i64_export = wasm_extern_as_func(exports.data[1]);
assert(i64_export != NULL);
wasm_func_t *many_export = wasm_extern_as_func(exports.data[2]);
assert(many_export != NULL);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
wasm_val_vec_t args;
args.size = 0;
wasm_val_vec_t results;
results.size = 0;
for (int i = 0; i < N; i++) {
trap = wasm_func_call(nop_export, &args, &results);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("nop", &start, &stop);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
wasm_val_t raw_results[1];
results.size = 1;
results.data = raw_results;
for (int i = 0; i < N; i++) {
trap = wasm_func_call(i64_export, &args, &results);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("i64", &start, &stop);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
results.size = 0;
for (int i = 0; i < N; i++) {
trap = wasm_func_call(many_export, &args, &results);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("many", &start, &stop);
wasm_extern_vec_delete(&exports);
wasm_func_delete(i64);
wasm_instance_delete(instance);
wasm_module_delete(module);
wasm_store_delete(store);
#else
wasmtime_store_t *store = wasmtime_store_new(engine, NULL, NULL);
wasmtime_context_t *context = wasmtime_store_context(store);
wasm_functype_t *ty = wasm_functype_new_0_1(wasm_valtype_new_i64());
wasmtime_func_t i64;
wasmtime_func_new(context, ty, host_i64, NULL, NULL, &i64);
wasm_valtype_t *i32_t = wasm_valtype_new_i32();
wasm_valtype_t* many_params_p[5] = {i32_t, i32_t, i32_t, i32_t, i32_t};
wasm_valtype_t* many_results_p[1] = {i32_t};
wasm_valtype_vec_t many_params, many_results;
wasm_valtype_vec_new(&many_params, 5, many_params_p);
wasm_valtype_vec_new(&many_results, 1, many_results_p);
wasm_functype_t *many_ty = wasm_functype_new(&many_params, &many_results);
wasmtime_func_t many;
wasmtime_func_new(context, many_ty, host_many, NULL, NULL, &many);
#ifdef STORAGE
wasm_functype_t *nop_ty = wasm_functype_new_0_0();
wasmtime_func_storage_t *nop_storage = wasmtime_func_storage_new(engine, nop_ty);
wasmtime_func_storage_t *i64_storage = wasmtime_func_storage_new(engine, ty);
#endif
wasmtime_module_t *module = NULL;
err = wasmtime_module_new(engine, (const uint8_t*)wasm.data, wasm.size, &module);
assert(err == NULL);
wasmtime_extern_t imports[2];
imports[0].kind = WASMTIME_EXTERN_FUNC;
imports[0].of.func = i64;
imports[1].kind = WASMTIME_EXTERN_FUNC;
imports[1].of.func = many;
wasmtime_instance_t instance;
wasm_trap_t *trap = NULL;
err = wasmtime_instance_new(context, module, imports, 2, &instance, &trap);
assert(err == NULL);
assert(trap == NULL);
wasmtime_extern_t nop_export;
bool ok = wasmtime_instance_export_get(context, &instance, "nop", 3, &nop_export);
assert(ok);
assert(nop_export.kind == WASMTIME_EXTERN_FUNC);
wasmtime_extern_t i64_export;
ok = wasmtime_instance_export_get(context, &instance, "i64", 3, &i64_export);
assert(ok);
assert(i64_export.kind == WASMTIME_EXTERN_FUNC);
wasmtime_extern_t many_export;
ok = wasmtime_instance_export_get(context, &instance, "many", 4, &many_export);
assert(ok);
assert(many_export.kind == WASMTIME_EXTERN_FUNC);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
for (int i = 0; i < N; i++) {
#ifdef STORAGE
err = wasmtime_func_call_with_storage(context, &nop_export.of.func, nop_storage, NULL, 0, NULL, 0, &trap);
#else
err = wasmtime_func_call(context, &nop_export.of.func, NULL, 0, NULL, 0, &trap);
#endif
assert(err == NULL);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("nop", &start, &stop);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
wasmtime_val_t ret;
for (int i = 0; i < N; i++) {
#ifdef STORAGE
err = wasmtime_func_call_with_storage(context, &i64_export.of.func, i64_storage, NULL, 0, &ret, 1, &trap);
#else
err = wasmtime_func_call(context, &i64_export.of.func, NULL, 0, &ret, 1, &trap);
#endif
assert(err == NULL);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("i64", &start, &stop);
rc = clock_gettime(CLOCK_MONOTONIC, &start);
assert(rc == 0);
for (int i = 0; i < N; i++) {
err = wasmtime_func_call(context, &many_export.of.func, NULL, 0, NULL, 0, &trap);
assert(err == NULL);
assert(trap == NULL);
}
rc = clock_gettime(CLOCK_MONOTONIC, &stop);
assert(rc == 0);
print_diff("many", &start, &stop);
#ifdef STORAGE
wasmtime_func_storage_delete(nop_storage);
wasmtime_func_storage_delete(i64_storage);
#endif
wasmtime_store_delete(store);
#endif
wasm_engine_delete(engine);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment