Skip to content

Commit

Permalink
perf(napi): optimize primitive napi functions (denoland#16163)
Browse files Browse the repository at this point in the history
This optimization applies on `napi_get_undefined`, `napi_get_null` &
`napi_get_boolean`.

```
# main

benchmark               time (avg)             (min … max)       p75       p99      p995
---------------------------------------------------------- -----------------------------
warmup              482.55 ps/iter   (462.5 ps … 15.67 ns)    475 ps    525 ps  829.1 ps
napi_get_undefined   25.07 ns/iter   (24.03 ns … 36.87 ns)  25.37 ns  27.09 ns  34.85 ns
```

```
# This patch

benchmark               time (avg)             (min … max)       p75       p99      p995
---------------------------------------------------------- -----------------------------
warmup              484.78 ps/iter    (462.5 ps … 14.4 ns)    475 ps  554.1 ps  583.3 ps
napi_get_undefined   15.52 ns/iter   (15.35 ns … 22.14 ns)  15.41 ns  17.18 ns  20.02 ns
```
  • Loading branch information
littledivy committed Oct 7, 2022
1 parent be80c57 commit e136bd8
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ opt-level = 3
opt-level = 3
[profile.release.package.deno_napi]
opt-level = 3
[profile.release.package.test_napi]
opt-level = 3
[profile.release.package.num-bigint-dig]
opt-level = 3
[profile.release.package.v8]
Expand Down
6 changes: 6 additions & 0 deletions cli/bench/napi/bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { loadTestLibrary } from "../../../test_napi/common.js";

const lib = loadTestLibrary();

Deno.bench("warmup", () => {});
Deno.bench("napi_get_undefined", () => lib.test_get_undefined(0));
10 changes: 10 additions & 0 deletions cli/bench/napi/bench_node.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { run, bench } from "mitata";
import { createRequire } from "module";

const require = createRequire(import.meta.url);
const lib = require("../../../test_napi.node");

bench("warmup", () => {});
bench("napi_get_undefined", () => lib.test_get_undefined(0));

run();
6 changes: 3 additions & 3 deletions cli/napi/js_native_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ fn napi_get_boolean(
) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> =
v8::Boolean::new(&mut env.scope(), value).into();
v8::Boolean::new(env.isolate(), value).into();
*result = value.into();
Ok(())
}
Expand Down Expand Up @@ -1520,7 +1520,7 @@ fn napi_get_new_target(
fn napi_get_null(env: *mut Env, result: *mut napi_value) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;

let value: v8::Local<v8::Value> = v8::null(&mut env.scope()).into();
let value: v8::Local<v8::Value> = v8::null(env.isolate()).into();
*result = value.into();
Ok(())
}
Expand Down Expand Up @@ -1611,7 +1611,7 @@ fn napi_get_typedarray_info(
#[napi_sym::napi_sym]
fn napi_get_undefined(env: *mut Env, result: *mut napi_value) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = v8::undefined(&mut env.scope()).into();
let value: v8::Local<v8::Value> = v8::undefined(env.isolate()).into();
*result = value.into();
Ok(())
}
Expand Down
4 changes: 3 additions & 1 deletion serde_v8/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::ser;
use serde::ser::Serialize;

use std::cell::RefCell;
use std::ops::DerefMut;

use crate::error::{Error, Result};
use crate::keys::v8_struct_key;
Expand Down Expand Up @@ -435,7 +436,8 @@ impl<'a, 'b, 'c> ser::Serializer for Serializer<'a, 'b, 'c> {
}

fn serialize_f64(self, v: f64) -> JsResult<'a> {
Ok(v8::Number::new(&mut self.scope.borrow_mut(), v).into())
let scope = &mut self.scope.borrow_mut();
Ok(v8::Number::new(scope.deref_mut(), v).into())
}

fn serialize_bool(self, v: bool) -> JsResult<'a> {
Expand Down
2 changes: 2 additions & 0 deletions test_napi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod callback;
pub mod coerce;
pub mod numbers;
pub mod object_wrap;
pub mod primitives;
pub mod promise;
pub mod properties;
pub mod strings;
Expand Down Expand Up @@ -67,6 +68,7 @@ unsafe extern "C" fn napi_register_module_v1(
numbers::init(env, exports);
typedarray::init(env, exports);
array::init(env, exports);
primitives::init(env, exports);
properties::init(env, exports);
promise::init(env, exports);
coerce::init(env, exports);
Expand Down
23 changes: 23 additions & 0 deletions test_napi/src/primitives.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use napi_sys::*;
use std::ptr;

extern "C" fn test_get_undefined(
env: napi_env,
_: napi_callback_info,
) -> napi_value {
let mut result = ptr::null_mut();
unsafe { napi_get_undefined(env, &mut result) };
result
}

pub fn init(env: napi_env, exports: napi_value) {
let properties = &[crate::new_property!(
env,
"test_get_undefined\0",
test_get_undefined
)];

unsafe {
napi_define_properties(env, exports, properties.len(), properties.as_ptr())
};
}

0 comments on commit e136bd8

Please sign in to comment.