Skip to content

Feat: Support creating warmed VM in the proxy wasm V8 VM API. #447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions include/proxy-wasm/null_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ struct NullVm : public WasmVm {
void terminate() override {}
bool usesWasmByteOrder() override { return false; }

void warm() override {}

std::string plugin_name_;
std::unique_ptr<NullVmPlugin> plugin_;
};
Expand Down
1 change: 1 addition & 0 deletions include/proxy-wasm/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

namespace proxy_wasm {

bool initV8Engine();
std::unique_ptr<WasmVm> createV8Vm();

} // namespace proxy_wasm
1 change: 1 addition & 0 deletions include/proxy-wasm/wamr.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

namespace proxy_wasm {

bool initWamrEngine();
std::unique_ptr<WasmVm> createWamrVm();

} // namespace proxy_wasm
5 changes: 5 additions & 0 deletions include/proxy-wasm/wasm_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ class WasmVm {
*/
virtual bool usesWasmByteOrder() = 0;

/**
* Warm the VM such as engine and runtime.
*/
virtual void warm() = 0;

bool isFailed() { return failed_ != FailState::Ok; }
void fail(FailState fail_state, std::string_view message) {
integration()->error(message);
Expand Down
1 change: 1 addition & 0 deletions include/proxy-wasm/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace proxy_wasm {

bool initWasmtimeEngine();
std::unique_ptr<WasmVm> createWasmtimeVm();

} // namespace proxy_wasm
18 changes: 17 additions & 1 deletion src/v8/v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class V8 : public WasmVm {
void terminate() override;
bool usesWasmByteOrder() override { return true; }

void warm() override;

private:
wasm::own<wasm::Trap> trap(std::string message);

Expand All @@ -124,6 +126,9 @@ class V8 : public WasmVm {
void getModuleFunctionImpl(std::string_view function_name,
std::function<R(ContextBase *, Args...)> *function);

// Initialize the V8 engine and store if necessary.
void initStore();

wasm::own<wasm::Store> store_;
wasm::own<wasm::Module> module_;
wasm::own<wasm::Shared<wasm::Module>> shared_module_;
Expand Down Expand Up @@ -260,9 +265,16 @@ template <typename T, typename U> constexpr T convertValTypesToArgsTuple(const U

// V8 implementation.

void V8::initStore() {
if (store_ != nullptr) {
return;
}
store_ = wasm::Store::make(engine());
}

bool V8::load(std::string_view bytecode, std::string_view precompiled,
const std::unordered_map<uint32_t, std::string> &function_names) {
store_ = wasm::Store::make(engine());
initStore();
if (store_ == nullptr) {
return false;
}
Expand Down Expand Up @@ -708,6 +720,8 @@ void V8::terminate() {
isolate->TerminateExecution();
}

void V8::warm() { initStore(); }

std::string V8::getFailMessage(std::string_view function_name, wasm::own<wasm::Trap> trap) {
auto message = "Function: " + std::string(function_name) + " failed: ";
message += std::string(trap->message().get(), trap->message().size());
Expand Down Expand Up @@ -741,6 +755,8 @@ std::string V8::getFailMessage(std::string_view function_name, wasm::own<wasm::T

} // namespace v8

bool initV8Engine() { return v8::engine() != nullptr; }

std::unique_ptr<WasmVm> createV8Vm() { return std::make_unique<v8::V8>(); }

} // namespace proxy_wasm
18 changes: 17 additions & 1 deletion src/wamr/wamr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class Wamr : public WasmVm {
void terminate() override {}
bool usesWasmByteOrder() override { return true; }

void warm() override;

private:
template <typename... Args>
void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name,
Expand All @@ -107,6 +109,9 @@ class Wamr : public WasmVm {
void getModuleFunctionImpl(std::string_view function_name,
std::function<R(ContextBase *, Args...)> *function);

// Initialize the Wamr store if necessary.
void initStore();

WasmStorePtr store_;
WasmModulePtr module_;
WasmSharedModulePtr shared_module_;
Expand All @@ -119,9 +124,16 @@ class Wamr : public WasmVm {
std::unordered_map<std::string, WasmFuncPtr> module_functions_;
};

void Wamr::initStore() {
if (store_ != nullptr) {
return;
}
store_ = wasm_store_new(engine());
}

bool Wamr::load(std::string_view bytecode, std::string_view precompiled,
const std::unordered_map<uint32_t, std::string> & /*function_names*/) {
store_ = wasm_store_new(engine());
initStore();
if (store_ == nullptr) {
return false;
}
Expand Down Expand Up @@ -697,8 +709,12 @@ void Wamr::getModuleFunctionImpl(std::string_view function_name,
};
};

void Wamr::warm() { initStore(); }

} // namespace wamr

bool initWamrEngine() { return wamr::engine() != nullptr; }

std::unique_ptr<WasmVm> createWamrVm() { return std::make_unique<wamr::Wamr>(); }

} // namespace proxy_wasm
19 changes: 16 additions & 3 deletions src/wasmedge/wasmedge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ class WasmEdge : public WasmVm {
};
FOR_ALL_WASM_VM_EXPORTS(_GET_MODULE_FUNCTION)
#undef _GET_MODULE_FUNCTION

void warm() override;

private:
template <typename... Args>
void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name,
Expand All @@ -284,6 +287,9 @@ class WasmEdge : public WasmVm {
void terminate() override {}
bool usesWasmByteOrder() override { return true; }

// Initialize the WasmEdge store if necessary.
void initStore();

WasmEdgeLoaderPtr loader_;
WasmEdgeValidatorPtr validator_;
WasmEdgeExecutorPtr executor_;
Expand Down Expand Up @@ -314,13 +320,18 @@ bool WasmEdge::load(std::string_view bytecode, std::string_view /*precompiled*/,
return true;
}

void WasmEdge::initStore() {
if (store_ != nullptr) {
return;
}
store_ = WasmEdge_StoreCreate();
}

bool WasmEdge::link(std::string_view /*debug_name*/) {
assert(ast_module_ != nullptr);

// Create store and register imports.
if (store_ == nullptr) {
store_ = WasmEdge_StoreCreate();
}
initStore();
if (store_ == nullptr) {
return false;
}
Expand Down Expand Up @@ -609,6 +620,8 @@ void WasmEdge::getModuleFunctionImpl(std::string_view function_name,
};
}

void WasmEdge::warm() { initStore(); }

} // namespace WasmEdge

std::unique_ptr<WasmVm> createWasmEdgeVm() { return std::make_unique<WasmEdge::WasmEdge>(); }
Expand Down
19 changes: 18 additions & 1 deletion src/wasmtime/wasmtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class Wasmtime : public WasmVm {
};
FOR_ALL_WASM_VM_EXPORTS(_GET_MODULE_FUNCTION)
#undef _GET_MODULE_FUNCTION

void warm() override;

private:
template <typename... Args>
void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name,
Expand All @@ -100,6 +103,9 @@ class Wasmtime : public WasmVm {
void terminate() override {}
bool usesWasmByteOrder() override { return true; }

// Initialize the Wasmtime store if necessary.
void initStore();

WasmStorePtr store_;
WasmModulePtr module_;
WasmSharedModulePtr shared_module_;
Expand All @@ -111,9 +117,16 @@ class Wasmtime : public WasmVm {
std::unordered_map<std::string, WasmFuncPtr> module_functions_;
};

void Wasmtime::initStore() {
if (store_ != nullptr) {
return;
}
store_ = wasm_store_new(engine());
}

bool Wasmtime::load(std::string_view bytecode, std::string_view /*precompiled*/,
const std::unordered_map<uint32_t, std::string> & /*function_names*/) {
store_ = wasm_store_new(engine());
initStore();
if (store_ == nullptr) {
return false;
}
Expand Down Expand Up @@ -693,8 +706,12 @@ void Wasmtime::getModuleFunctionImpl(std::string_view function_name,
};
};

void Wasmtime::warm() { initStore(); }

} // namespace wasmtime

bool initWasmtimeEngine() { return wasmtime::engine() != nullptr; }

std::unique_ptr<WasmVm> createWasmtimeVm() { return std::make_unique<wasmtime::Wasmtime>(); }

} // namespace proxy_wasm
40 changes: 40 additions & 0 deletions test/wasm_vm_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,46 @@ INSTANTIATE_TEST_SUITE_P(WasmEngines, TestVm, testing::ValuesIn(getWasmEngines()
return info.param;
});

TEST_P(TestVm, Init) {
std::chrono::time_point<std::chrono::steady_clock> time2;

auto time1 = std::chrono::steady_clock::now();
if (engine_ == "v8") {
#if defined(PROXY_WASM_HOST_ENGINE_V8)
EXPECT_TRUE(proxy_wasm::initV8Engine());
time2 = std::chrono::steady_clock::now();
EXPECT_TRUE(proxy_wasm::initV8Engine());
#endif
} else if (engine_ == "wamr") {
#if defined(PROXY_WASM_HOST_ENGINE_WAMR)
EXPECT_TRUE(proxy_wasm::initWamrEngine());
time2 = std::chrono::steady_clock::now();
EXPECT_TRUE(proxy_wasm::initWamrEngine());
#endif
} else if (engine_ == "wasmtime") {
#if defined(PROXY_WASM_HOST_ENGINE_WASMTIME)
EXPECT_TRUE(proxy_wasm::initWasmtimeEngine());
time2 = std::chrono::steady_clock::now();
EXPECT_TRUE(proxy_wasm::initWasmtimeEngine());
#endif
} else {
return;
}
auto time3 = std::chrono::steady_clock::now();

auto cold = std::chrono::duration_cast<std::chrono::nanoseconds>(time2 - time1).count();
auto warm = std::chrono::duration_cast<std::chrono::nanoseconds>(time3 - time2).count();

std::cout << "\"cold\" engine time: " << cold << "ns" << std::endl;
std::cout << "\"warm\" engine time: " << warm << "ns" << std::endl;

// Verify that getting a "warm" engine takes less than 10us.
EXPECT_LE(warm, 10000);

// Verify that getting a "warm" engine takes at least 50x less time than getting a "cold" one.
EXPECT_LE(warm * 50, cold);
}

TEST_P(TestVm, Basic) {
if (engine_ == "wasmedge") {
EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::NotCloneable);
Expand Down