mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
perf(ext/ffi): leverage V8 Fast Calls (#15125)
This commit is contained in:
parent
b3b3018273
commit
20cbd7f0f8
3 changed files with 209 additions and 62 deletions
|
@ -227,6 +227,7 @@ fn v8_init(
|
|||
" --wasm-test-streaming",
|
||||
" --harmony-import-assertions",
|
||||
" --no-validate-asm",
|
||||
" --turbo_fast_api_calls",
|
||||
);
|
||||
|
||||
if predictable {
|
||||
|
|
|
@ -10,6 +10,7 @@ use deno_core::futures::channel::mpsc;
|
|||
use deno_core::futures::Future;
|
||||
use deno_core::include_js_files;
|
||||
use deno_core::op;
|
||||
use deno_core::v8::fast_api;
|
||||
use std::sync::mpsc::sync_channel;
|
||||
|
||||
use deno_core::serde_json::json;
|
||||
|
@ -604,7 +605,7 @@ where
|
|||
match foreign_fn.non_blocking {
|
||||
// Generate functions for synchronous calls.
|
||||
Some(false) | None => {
|
||||
let function = make_sync_fn(scope, Box::leak(sym));
|
||||
let function = make_sync_fn(scope, sym);
|
||||
obj.set(scope, func_key.into(), function.into());
|
||||
}
|
||||
// This optimization is not yet supported for non-blocking calls.
|
||||
|
@ -623,13 +624,91 @@ where
|
|||
))
|
||||
}
|
||||
|
||||
pub struct FfiFastCallTemplate {
|
||||
args: Box<[fast_api::Type]>,
|
||||
ret: fast_api::CType,
|
||||
symbol_ptr: *const c_void,
|
||||
}
|
||||
|
||||
impl fast_api::FastFunction for FfiFastCallTemplate {
|
||||
type Signature = ();
|
||||
fn function(&self) -> Self::Signature {}
|
||||
|
||||
fn raw(&self) -> *const c_void {
|
||||
self.symbol_ptr
|
||||
}
|
||||
fn args(&self) -> &'static [fast_api::Type] {
|
||||
Box::leak(self.args.clone())
|
||||
}
|
||||
fn return_type(&self) -> fast_api::CType {
|
||||
self.ret
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&NativeType> for fast_api::Type {
|
||||
fn from(native_type: &NativeType) -> Self {
|
||||
match native_type {
|
||||
NativeType::U8 | NativeType::U16 | NativeType::U32 => {
|
||||
fast_api::Type::Uint32
|
||||
}
|
||||
NativeType::I8 | NativeType::I16 | NativeType::I32 => {
|
||||
fast_api::Type::Int32
|
||||
}
|
||||
NativeType::F32 => fast_api::Type::Float32,
|
||||
NativeType::F64 => fast_api::Type::Float64,
|
||||
NativeType::Void => fast_api::Type::Void,
|
||||
NativeType::Function
|
||||
| NativeType::Pointer
|
||||
| NativeType::I64
|
||||
| NativeType::ISize
|
||||
| NativeType::U64
|
||||
| NativeType::USize => {
|
||||
panic!("Cannot be fast api")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fast_api(rv: NativeType) -> bool {
|
||||
!matches!(
|
||||
rv,
|
||||
NativeType::Function
|
||||
| NativeType::Pointer
|
||||
| NativeType::I64
|
||||
| NativeType::ISize
|
||||
| NativeType::U64
|
||||
| NativeType::USize
|
||||
)
|
||||
}
|
||||
|
||||
// Create a JavaScript function for synchronous FFI call to
|
||||
// the given symbol.
|
||||
fn make_sync_fn<'s>(
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
sym: *mut Symbol,
|
||||
sym: Box<Symbol>,
|
||||
) -> v8::Local<'s, v8::Function> {
|
||||
let func = v8::Function::builder(
|
||||
let mut fast_ffi_templ = None;
|
||||
|
||||
if !sym.parameter_types.iter().any(|t| !is_fast_api(*t))
|
||||
&& is_fast_api(sym.result_type)
|
||||
{
|
||||
let mut args = sym
|
||||
.parameter_types
|
||||
.iter()
|
||||
.map(|t| t.into())
|
||||
.collect::<Vec<_>>();
|
||||
if args.is_empty() {
|
||||
args.push(fast_api::Type::V8Value);
|
||||
}
|
||||
fast_ffi_templ = Some(FfiFastCallTemplate {
|
||||
args: args.into_boxed_slice(),
|
||||
ret: (&fast_api::Type::from(&sym.result_type)).into(),
|
||||
symbol_ptr: sym.ptr.as_ptr() as *const c_void,
|
||||
});
|
||||
}
|
||||
|
||||
let sym = Box::leak(sym);
|
||||
let builder = v8::FunctionTemplate::builder(
|
||||
|scope: &mut v8::HandleScope,
|
||||
args: v8::FunctionCallbackArguments,
|
||||
mut rv: v8::ReturnValue| {
|
||||
|
@ -650,9 +729,14 @@ fn make_sync_fn<'s>(
|
|||
};
|
||||
},
|
||||
)
|
||||
.data(v8::External::new(scope, sym as *mut _).into())
|
||||
.build(scope)
|
||||
.unwrap();
|
||||
.data(v8::External::new(scope, sym as *mut Symbol as *mut _).into());
|
||||
|
||||
let func = if let Some(fast_ffi_templ) = fast_ffi_templ {
|
||||
builder.build_fast(scope, fast_ffi_templ)
|
||||
} else {
|
||||
builder.build(scope)
|
||||
};
|
||||
let func = func.get_function(scope).unwrap();
|
||||
|
||||
let weak = v8::Weak::with_finalizer(
|
||||
scope,
|
||||
|
|
|
@ -11,6 +11,7 @@ const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`;
|
|||
|
||||
const dylib = Deno.dlopen(libPath, {
|
||||
"nop": { parameters: [], result: "void" },
|
||||
"add_u32": { parameters: ["u32", "u32"], result: "u32" },
|
||||
"nop_u8": { parameters: ["u8"], result: "void" },
|
||||
"nop_i8": { parameters: ["i8"], result: "void" },
|
||||
"nop_u16": { parameters: ["u16"], result: "void" },
|
||||
|
@ -220,228 +221,288 @@ const dylib = Deno.dlopen(libPath, {
|
|||
},
|
||||
});
|
||||
|
||||
const { nop } = dylib.symbols;
|
||||
Deno.bench("nop()", () => {
|
||||
dylib.symbols.nop();
|
||||
nop();
|
||||
});
|
||||
|
||||
const { add_u32 } = dylib.symbols;
|
||||
Deno.bench("add_u32()", () => {
|
||||
add_u32(1, 2);
|
||||
});
|
||||
|
||||
const { nop_u8 } = dylib.symbols;
|
||||
Deno.bench("nop_u8()", () => {
|
||||
dylib.symbols.nop_u8(100);
|
||||
nop_u8(100);
|
||||
});
|
||||
|
||||
const { nop_i8 } = dylib.symbols;
|
||||
Deno.bench("nop_i8()", () => {
|
||||
dylib.symbols.nop_i8(100);
|
||||
nop_i8(100);
|
||||
});
|
||||
|
||||
const { nop_u16 } = dylib.symbols;
|
||||
Deno.bench("nop_u16()", () => {
|
||||
dylib.symbols.nop_u16(100);
|
||||
nop_u16(100);
|
||||
});
|
||||
|
||||
const { nop_i16 } = dylib.symbols;
|
||||
Deno.bench("nop_i16()", () => {
|
||||
dylib.symbols.nop_i16(100);
|
||||
nop_i16(100);
|
||||
});
|
||||
|
||||
const { nop_u32 } = dylib.symbols;
|
||||
Deno.bench("nop_u32()", () => {
|
||||
dylib.symbols.nop_u32(100);
|
||||
nop_u32(100);
|
||||
});
|
||||
|
||||
const { nop_i32 } = dylib.symbols;
|
||||
Deno.bench("nop_i32()", () => {
|
||||
dylib.symbols.nop_i32(100);
|
||||
nop_i32(100);
|
||||
});
|
||||
|
||||
const { nop_u64 } = dylib.symbols;
|
||||
Deno.bench("nop_u64()", () => {
|
||||
dylib.symbols.nop_u64(100);
|
||||
nop_u64(100);
|
||||
});
|
||||
|
||||
const { nop_i64 } = dylib.symbols;
|
||||
Deno.bench("nop_i64()", () => {
|
||||
dylib.symbols.nop_i64(100);
|
||||
nop_i64(100);
|
||||
});
|
||||
|
||||
const { nop_usize } = dylib.symbols;
|
||||
Deno.bench("nop_usize()", () => {
|
||||
dylib.symbols.nop_usize(100);
|
||||
nop_usize(100n);
|
||||
});
|
||||
|
||||
const { nop_isize } = dylib.symbols;
|
||||
Deno.bench("nop_isize()", () => {
|
||||
dylib.symbols.nop_isize(100);
|
||||
nop_isize(100n);
|
||||
});
|
||||
|
||||
const { nop_f32 } = dylib.symbols;
|
||||
Deno.bench("nop_f32()", () => {
|
||||
dylib.symbols.nop_f32(100);
|
||||
nop_f32(100.1);
|
||||
});
|
||||
|
||||
const { nop_f64 } = dylib.symbols;
|
||||
Deno.bench("nop_f64()", () => {
|
||||
dylib.symbols.nop_f64(100);
|
||||
nop_f64(100.1);
|
||||
});
|
||||
|
||||
const { nop_buffer } = dylib.symbols;
|
||||
const buffer = new Uint8Array(8).fill(5);
|
||||
Deno.bench("nop_buffer()", () => {
|
||||
dylib.symbols.nop_buffer(buffer);
|
||||
nop_buffer(buffer);
|
||||
});
|
||||
|
||||
const { return_u8 } = dylib.symbols;
|
||||
Deno.bench("return_u8()", () => {
|
||||
dylib.symbols.return_u8();
|
||||
return_u8();
|
||||
});
|
||||
|
||||
const { return_i8 } = dylib.symbols;
|
||||
Deno.bench("return_i8()", () => {
|
||||
dylib.symbols.return_i8();
|
||||
return_i8();
|
||||
});
|
||||
|
||||
const { return_u16 } = dylib.symbols;
|
||||
Deno.bench("return_u16()", () => {
|
||||
dylib.symbols.return_u16();
|
||||
return_u16();
|
||||
});
|
||||
|
||||
const { return_i16 } = dylib.symbols;
|
||||
Deno.bench("return_i16()", () => {
|
||||
dylib.symbols.return_i16();
|
||||
return_i16();
|
||||
});
|
||||
|
||||
const { return_u32 } = dylib.symbols;
|
||||
Deno.bench("return_u32()", () => {
|
||||
dylib.symbols.return_u32();
|
||||
return_u32();
|
||||
});
|
||||
|
||||
const { return_i32 } = dylib.symbols;
|
||||
Deno.bench("return_i32()", () => {
|
||||
dylib.symbols.return_i32();
|
||||
return_i32();
|
||||
});
|
||||
|
||||
const { return_u64 } = dylib.symbols;
|
||||
Deno.bench("return_u64()", () => {
|
||||
dylib.symbols.return_u64();
|
||||
return_u64();
|
||||
});
|
||||
|
||||
const { return_i64 } = dylib.symbols;
|
||||
Deno.bench("return_i64()", () => {
|
||||
dylib.symbols.return_i64();
|
||||
return_i64();
|
||||
});
|
||||
|
||||
const { return_usize } = dylib.symbols;
|
||||
Deno.bench("return_usize()", () => {
|
||||
dylib.symbols.return_usize();
|
||||
return_usize();
|
||||
});
|
||||
|
||||
const { return_isize } = dylib.symbols;
|
||||
Deno.bench("return_isize()", () => {
|
||||
dylib.symbols.return_isize();
|
||||
return_isize();
|
||||
});
|
||||
|
||||
const { return_f32 } = dylib.symbols;
|
||||
Deno.bench("return_f32()", () => {
|
||||
dylib.symbols.return_f32();
|
||||
return_f32();
|
||||
});
|
||||
|
||||
const { return_f64 } = dylib.symbols;
|
||||
Deno.bench("return_f64()", () => {
|
||||
dylib.symbols.return_f64();
|
||||
return_f64();
|
||||
});
|
||||
|
||||
const { return_buffer } = dylib.symbols;
|
||||
Deno.bench("return_buffer()", () => {
|
||||
dylib.symbols.return_buffer();
|
||||
return_buffer();
|
||||
});
|
||||
|
||||
// Nonblocking calls
|
||||
|
||||
const { nop_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_nonblocking();
|
||||
await nop_nonblocking();
|
||||
});
|
||||
|
||||
const { nop_u8_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_u8_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_u8_nonblocking(100);
|
||||
await nop_u8_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_i8_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_i8_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_i8_nonblocking(100);
|
||||
await nop_i8_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_u16_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_u16_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_u16_nonblocking(100);
|
||||
await nop_u16_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_i16_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_i16_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_i16_nonblocking(100);
|
||||
await nop_i16_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_u32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_u32_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_u32_nonblocking(100);
|
||||
await nop_u32_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_i32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_i32_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_i32_nonblocking(100);
|
||||
await nop_i32_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_u64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_u64_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_u64_nonblocking(100);
|
||||
await nop_u64_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_i64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_i64_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_i64_nonblocking(100);
|
||||
await nop_i64_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_usize_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_usize_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_usize_nonblocking(100);
|
||||
await nop_usize_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_isize_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_isize_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_isize_nonblocking(100);
|
||||
await nop_isize_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_f32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_f32_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_f32_nonblocking(100);
|
||||
await nop_f32_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_f64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_f64_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_f64_nonblocking(100);
|
||||
await nop_f64_nonblocking(100);
|
||||
});
|
||||
|
||||
const { nop_buffer_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_buffer_nonblocking()", async () => {
|
||||
await dylib.symbols.nop_buffer_nonblocking(buffer);
|
||||
await nop_buffer_nonblocking(buffer);
|
||||
});
|
||||
|
||||
const { return_u8_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_u8_nonblocking()", async () => {
|
||||
await dylib.symbols.return_u8_nonblocking();
|
||||
await return_u8_nonblocking();
|
||||
});
|
||||
|
||||
const { return_i8_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_i8_nonblocking()", async () => {
|
||||
await dylib.symbols.return_i8_nonblocking();
|
||||
await return_i8_nonblocking();
|
||||
});
|
||||
|
||||
const { return_u16_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_u16_nonblocking()", async () => {
|
||||
await dylib.symbols.return_u16_nonblocking();
|
||||
await return_u16_nonblocking();
|
||||
});
|
||||
|
||||
const { return_i16_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_i16_nonblocking()", async () => {
|
||||
await dylib.symbols.return_i16_nonblocking();
|
||||
await return_i16_nonblocking();
|
||||
});
|
||||
|
||||
const { return_u32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_u32_nonblocking()", async () => {
|
||||
await dylib.symbols.return_u32_nonblocking();
|
||||
await return_u32_nonblocking();
|
||||
});
|
||||
|
||||
const { return_i32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_i32_nonblocking()", async () => {
|
||||
await dylib.symbols.return_i32_nonblocking();
|
||||
await return_i32_nonblocking();
|
||||
});
|
||||
|
||||
const { return_u64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_u64_nonblocking()", async () => {
|
||||
await dylib.symbols.return_u64_nonblocking();
|
||||
await return_u64_nonblocking();
|
||||
});
|
||||
|
||||
const { return_i64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_i64_nonblocking()", async () => {
|
||||
await dylib.symbols.return_i64_nonblocking();
|
||||
await return_i64_nonblocking();
|
||||
});
|
||||
|
||||
const { return_usize_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_usize_nonblocking()", async () => {
|
||||
await dylib.symbols.return_usize_nonblocking();
|
||||
await return_usize_nonblocking();
|
||||
});
|
||||
|
||||
const { return_isize_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_isize_nonblocking()", async () => {
|
||||
await dylib.symbols.return_isize_nonblocking();
|
||||
await return_isize_nonblocking();
|
||||
});
|
||||
|
||||
const { return_f32_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_f32_nonblocking()", async () => {
|
||||
await dylib.symbols.return_f32_nonblocking();
|
||||
await return_f32_nonblocking();
|
||||
});
|
||||
|
||||
const { return_f64_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_f64_nonblocking()", async () => {
|
||||
await dylib.symbols.return_f64_nonblocking();
|
||||
await return_f64_nonblocking();
|
||||
});
|
||||
|
||||
const { return_buffer_nonblocking } = dylib.symbols;
|
||||
Deno.bench("return_buffer_nonblocking()", async () => {
|
||||
await dylib.symbols.return_buffer_nonblocking();
|
||||
await return_buffer_nonblocking();
|
||||
});
|
||||
|
||||
const { nop_many_parameters } = dylib.symbols;
|
||||
const buffer2 = new Uint8Array(8).fill(25);
|
||||
Deno.bench("nop_many_parameters()", () => {
|
||||
dylib.symbols.nop_many_parameters(
|
||||
nop_many_parameters(
|
||||
135,
|
||||
47,
|
||||
356,
|
||||
|
@ -471,8 +532,9 @@ Deno.bench("nop_many_parameters()", () => {
|
|||
);
|
||||
});
|
||||
|
||||
const { nop_many_parameters_nonblocking } = dylib.symbols;
|
||||
Deno.bench("nop_many_parameters_nonblocking()", () => {
|
||||
dylib.symbols.nop_many_parameters_nonblocking(
|
||||
nop_many_parameters_nonblocking(
|
||||
135,
|
||||
47,
|
||||
356,
|
||||
|
|
Loading…
Add table
Reference in a new issue