Skip to content

Instantly share code, notes, and snippets.

@mendes5
Last active February 5, 2021 05:03
Show Gist options
  • Select an option

  • Save mendes5/43d1252142dae0e4339848608d8b7128 to your computer and use it in GitHub Desktop.

Select an option

Save mendes5/43d1252142dae0e4339848608d8b7128 to your computer and use it in GitHub Desktop.
V8 vs Deno Call Overhead Test
fn add(
scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
let first = match v8::Local::<v8::Number>::try_from(args.get(0)) {
Ok(s) => s.value(),
Err(_) => {
let msg = v8::String::new(scope, "Invalid argument").unwrap();
let exception = v8::Exception::type_error(scope, msg);
scope.throw_exception(exception);
return;
}
};
let second = match v8::Local::<v8::Number>::try_from(args.get(1)) {
Ok(s) => s.value(),
Err(_) => {
let msg = v8::String::new(scope, "Invalid argument").unwrap();
let exception = v8::Exception::type_error(scope, msg);
scope.throw_exception(exception);
return;
}
};
let result = v8::Number::new(scope, first + second);
rv.set(result.into())
}
// Then at: core/bindings.rs:151
let add_key = v8::String::new(scope, "add").unwrap();
let add_tmpl = v8::FunctionTemplate::new(scope, add);
let add_val = add_tmpl.get_function(scope).unwrap();
core_val.set(scope, add_key.into(), add_val.into());
use deno_core::json_op_sync;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
use deno_core::Op;
use deno_core::RuntimeOptions;
use futures;
use std::io::Write;
use std::path::Path;
fn main() {
// Create the runtime
let mut runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(std::rc::Rc::new(deno_core::FsModuleLoader)),
..Default::default()
});
// Register our add op using the deno api
runtime.register_op(
"op_add",
json_op_sync(|_state, json, _| {
let args: [f64; 2] = serde_json::from_value(json)?;
Ok(serde_json::Value::from(args[0] + args[1]))
}),
);
// print function
runtime.register_op(
"op_print",
|_state, zero_copy| {
let mut out = std::io::stdout();
for buf in zero_copy {
out.write_all(&buf).unwrap();
}
Op::Sync(Box::new([]))
},
);
// Read module
let js_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("index.js");
let main_module = ModuleSpecifier::resolve_url_or_path(&js_path.to_string_lossy()).expect("Bah");
let mod_id = futures::executor::block_on(runtime.load_module(&main_module, None)).expect("Failed to load");
// Execute
futures::executor::block_on(runtime.mod_evaluate(mod_id)).unwrap();
}
// Ops = How many times the engine can call the function `add(x, y)` in 10 seconds
// Using: taskset 0x00000001
// First Run
[CoreJS] Ops 226.143.248
[WebAssembly] Ops 150.738.804
[V8 API] Ops 104.212.510
[DenoDispatch] Ops 3.305.002
// Second Run
[CoreJS] Ops 223.669.638
[WebAssembly] Ops 145.839.616
[V8 API] Ops 102.851.270
[DenoDispatch] Ops 3.229.429
// Third Run
[CoreJS] Ops 224.698.617
[WebAssembly] Ops 153.185.228
[V8 API] Ops 103.629.759
[DenoDispatch] Ops 3.230.980
Deno.core.ops();
function print(value) {
Deno.core.dispatchByName('op_print', Deno.core.encode(value.toString()), new Uint8Array([10]));
}
{
// Baseline JS add function, probably has zero call
// overhead as it is probably inlined
const add = (a, b) => a + b;
let reduced = 0;
let ops = 0;
const start = Date.now();
while (Date.now() - start < 10000) {
reduced += add(1,1);
ops++;
}
const end = Date.now();
print("\n\n[CoreJS] Runtime " + (end - start));
print("[CoreJS] Result " + reduced);
print("[CoreJS] Ops " + ops);
}
{
let reduced = 0;
let ops = 0;
const start = Date.now();
// Webassembly module to add 2 numbers
const bytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
]);
const module = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(module);
while (Date.now() - start < 10000) {
reduced += instance.exports.add(3, 4);
ops++;
}
const end = Date.now();
print("\n\n[WebAssembly] Runtime " + (end - start));
print("[WebAssembly] Result " + reduced);
print("[WebAssembly] Ops " + ops);
}
{
let reduced = 0;
let ops = 0;
const start = Date.now();
while (Date.now() - start < 10000) {
// Uses the function registered using the v8 API
reduced += Deno.core.add(1,1);
ops++;
}
const end = Date.now();
print("\n\n[V8 API] Runtime " + (end - start));
print("[V8 API] Result " + reduced);
print("[V8 API] Ops " + ops);
}
{
let reduced = 0;
let ops = 0;
const start = Date.now();
while (Date.now() - start < 10000) {
// Adds using the Deno ops api
reduced += JSON.parse(Deno.core.decode(Deno.core.dispatchByName('op_add', Deno.core.encode(JSON.stringify([1, 1]))))).ok;
ops++;
}
const end = Date.now();
print("\n\n[DenoDispatch] Runtime " + (end - start));
print("[DenoDispatch] Result " + reduced);
print("[DenoDispatch] Ops " + ops);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment