-
-
Save alexcrichton/e3ad76042c847981ab064e59325635aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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