The Second State VM (SSVM) is a high-performance WebAssembly runtime optimized for server-side applications. This project provides support for accessing SSVM as a Node.js addon. It allows Node.js applications to call WebAssembly functions written in Rust or other high-performance languages. Why do you want to run WebAssembly on the server-side? The SSVM addon could interact with the wasm files generated by the ssvmup compiler tool.
SSVM Node.js Addon is in active development.
In the current stage, our prebuilt version only supports x86_64 Linux.
Or you could use --build-from-source
flag to build from source during addon installation.
After SSVM Napi 0.4.0 release, we upgrade the base image from Ubuntu 18.04
to Ubuntu 20.04
.
Users should install the dependencies by the following requirments:
For the tensorflow extensions:
wget https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-2.4.0.tar.gz \
&& tar -C /usr/local -xzf libtensorflow-cpu-linux-x86_64-2.4.0.tar.gz \
&& ldconfig
# Download TensorFlow deps
wget https://github.com/second-state/ssvm-tensorflow-deps/releases/download/0.1.0/ssvm-tensorflow-deps-lite-0.1.0-linux-x64.tar.gz
tar -zxvf ssvm-tensorflow-deps-lite-0.1.0-linux-x64.tar.gz
cp ./libtensorflowlite_c.so /usr/local/lib
$ docker pull secondstate/ssvm-extensions
# Or you can build it on your local environment.
$ docker build . -f utils/docker/Dockerfile -t secondstate/ssvm-extensions
$ sudo apt list | grep llvm
...omitted...
llvm-dev/focal,now 1:10.0-50~exp1 amd64 [installed]
llvm-runtime/focal,now 1:10.0-50~exp1 amd64 [installed,automatic]
llvm/focal,now 1:10.0-50~exp1 amd64 [installed,automatic]
...omitted...
# If the version is 1:10.x, then your llvm version is correct.
$ strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
...omitted...
GLIBCXX_3.4.24
GLIBCXX_3.4.25
GLIBCXX_3.4.26
GLIBCXX_3.4.27
GLIBCXX_3.4.28
GLIBCXX_DEBUG_MESSAGE_LENGTH
# If you can find GLIBCXX_3.4.28 in the output, then your libstdc++6 version is correct.
Please refer to Tutorial: A Wasm-Bindgen application.
Please refer to Tutorial: A standalone wasm32-wasi application.
ssvm.VM(wasm, ssvm_options) -> vm_instance
wasm
: Input wasm file, can be the following two formats:
/tmp/hello.wasm
)options
: An options object for setup the SSVM execution environment.
options
args
[]
.env
process.env
that Wasm application will get as its environment variables. Default: {}
.preopens
{'/sandbox': '/some/real/path/that/wasm/can/access'}
Default: {}
.EnableWasiStartFunction
main()
, you should set this to true
. Default: false
.EnableAOT
false
.EnableMeasurement
false
.AllowCommands
[]
.AllowAllCommands
AllowCommands
. Default: false
.vm_instance
: A ssvm instance.Start() -> Integer
_start()
and expect the return value type is Integer
which represents the error code from main()
.args
in wasi options
.let error_code = Start();
Run(function_name, args...) -> void
function_name
with args
and expect the return value type is void
.function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
Run("Print", 1234);
RunInt(function_name, args...) -> Integer
function_name
with args
and expect the return value type is Integer
(Int32).function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunInt("Add", 1, 2);
// result should be 3
RunUInt(function_name, args...) -> Integer
function_name
with args
and expect the return value type is Integer
(UInt32).function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunInt("Add", 1, 2);
// result should be 3
RunInt64(function_name, args...) -> BigInt
function_name
with args
and expect the return value type is BigInt
(Int64).function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunInt("Add", 1, 2);
// result should be 3
RunUInt64(function_name, args...) -> BigInt
function_name
with args
and expect the return value type is BigInt
(UInt64).function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunInt("Add", 1, 2);
// result should be 3
RunString(function_name, args...) -> String
function_name
with args
and expect the return value type is String
.function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunString("PrintMathScore", "Amy", 98);
// result: "Amy’s math score is 98".
RunUint8Array(function_name, args...) -> Uint8Array
function_name
with args
and expect the return value type is Uint8Array
.function_name
args
<Integer/String/Uint8Array>*: The function arguments. The delimiter is ,
let result = RunUint8Array("Hash", "Hello, world!");
// result: "[12, 22, 33, 42, 51]".
Compile(output_filename) -> boolean
output_filename
.false
when the compilation failed.
// Compile only
let vm = ssvm.VM("/path/to/wasm/file", options);
vm.Compile("/path/to/aot/file");
// When you want to run the compiled file let vm = ssvm.VM("/path/to/aot/file", options); vm.RunXXX("Func", args);
#### `GetStatistics() -> Object`
* If you want to enable measurement, set the option `EnableMeasurement` to `true`. But please notice that enabling measurement will significantly affect performance.
* Get the statistics of execution runtime.
* Return Value `Statistics` <Object>
* `Measure` -> <Boolean>: To show if the measurement is enabled or not.
* `TotalExecutionTime` -> <Integer>: Total execution time (Wasm exeuction time + Host function execution time) in `ns` unit.
* `WasmExecutionTime` -> <Integer>: Wasm instructions execution time in `ns` unit.
* `HostFunctionExecutionTime` -> <Integer>: Host functions (e.g. eei or wasi functions) execution time in `ns` unit.
* `InstructionCount` -> <Integer>: The number of executed instructions in this execution.
* `TotalGasCost` -> <Integer>: The cost of this execution.
* `InstructionPerSecond` -> <Float>: The instructions per second of this execution.
```javascript
let result = RunInt("Add", 1, 2);
// result should be 3
let stat = GetStatistics();
/*
If the `EnableMeasurement: true`:
stat = Statistics: {
Measure: true,
TotalExecutionTime: 1512,
WasmExecutionTime: 1481,
HostFunctionExecutionTime: 31,
InstructionCount: 27972,
TotalGasCost: 27972,
InstructionPerSecond: 18887238.35246455
}
Else:
stat = Statistics: {
Measure: false
}
*/