test(napi): add memory tests for Reference
This commit is contained in:
parent
6a252c70d2
commit
63a557f6cc
10 changed files with 110 additions and 27 deletions
|
@ -30,6 +30,8 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T>(
|
||||||
REFERENCE_MAP.with(|reference_map| reference_map.borrow_mut().remove(&finalize_data))
|
REFERENCE_MAP.with(|reference_map| reference_map.borrow_mut().remove(&finalize_data))
|
||||||
{
|
{
|
||||||
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
|
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
|
||||||
|
debug_assert!(Rc::strong_count(&finalize_callbacks_rc) == 1);
|
||||||
|
debug_assert!(Rc::weak_count(&finalize_callbacks_rc) == 0);
|
||||||
let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
|
let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
|
||||||
finalize();
|
finalize();
|
||||||
let delete_reference_status = unsafe { sys::napi_delete_reference(env, ref_val) };
|
let delete_reference_status = unsafe { sys::napi_delete_reference(env, ref_val) };
|
||||||
|
|
|
@ -16,7 +16,9 @@ napi = { path = "../crates/napi", features = [
|
||||||
"latin1",
|
"latin1",
|
||||||
"compat-mode",
|
"compat-mode",
|
||||||
] }
|
] }
|
||||||
napi-derive = { path = "../crates/macro", features = ["compat-mode"] }
|
napi-derive = { path = "../crates/macro", default-features = false, features = [
|
||||||
|
"compat-mode",
|
||||||
|
] }
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createSuite } from './test-util.mjs'
|
import { createSuite } from './test-util.mjs'
|
||||||
|
|
||||||
|
await createSuite('reference')
|
||||||
await createSuite('tokio-future')
|
await createSuite('tokio-future')
|
||||||
await createSuite('serde')
|
await createSuite('serde')
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node ../cli/scripts/index.js build --release"
|
"build": "node ../cli/scripts/index.js build --release --js false"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colorette": "^2.0.16",
|
"colorette": "^2.0.16",
|
||||||
|
|
32
memory-testing/reference.mjs
Normal file
32
memory-testing/reference.mjs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
|
import { displayMemoryUsageFromNode } from './util.mjs'
|
||||||
|
|
||||||
|
const initialMemoryUsage = process.memoryUsage()
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
|
||||||
|
const { MemoryHolder } = require(`./index.node`)
|
||||||
|
|
||||||
|
const sleep = () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve()
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
let i = 1
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
|
while (true) {
|
||||||
|
const holder = new MemoryHolder(1024 * 1024)
|
||||||
|
for (const _ of Array.from({ length: 100 })) {
|
||||||
|
const child = holder.createReference()
|
||||||
|
child.count()
|
||||||
|
}
|
||||||
|
if (i % 100 === 0) {
|
||||||
|
displayMemoryUsageFromNode(initialMemoryUsage)
|
||||||
|
await sleep()
|
||||||
|
global.gc()
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
const displayMemoryUsageFromNode = require('./util')
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
|
import { displayMemoryUsageFromNode } from './util.mjs'
|
||||||
|
|
||||||
const initialMemoryUsage = process.memoryUsage()
|
const initialMemoryUsage = process.memoryUsage()
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
|
||||||
const api = require(`./index.node`)
|
const api = require(`./index.node`)
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -27,7 +31,7 @@ const data = {
|
||||||
let i = 1
|
let i = 1
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
api.convertFromJS(data)
|
api.fromJs(data)
|
||||||
if (i % 100000 === 0) {
|
if (i % 100000 === 0) {
|
||||||
displayMemoryUsageFromNode(initialMemoryUsage)
|
displayMemoryUsageFromNode(initialMemoryUsage)
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
use napi::{bindgen_prelude::*, Env};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate napi_derive;
|
extern crate napi_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -34,8 +36,8 @@ pub struct Room {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function]
|
#[napi]
|
||||||
fn test_async(ctx: napi::CallContext) -> napi::Result<napi::JsObject> {
|
pub fn test_async(env: Env) -> napi::Result<napi::JsObject> {
|
||||||
let data = serde_json::json!({
|
let data = serde_json::json!({
|
||||||
"findFirstBooking": {
|
"findFirstBooking": {
|
||||||
"id": "ckovh15xa104945sj64rdk8oas",
|
"id": "ckovh15xa104945sj64rdk8oas",
|
||||||
|
@ -57,26 +59,62 @@ fn test_async(ctx: napi::CallContext) -> napi::Result<napi::JsObject> {
|
||||||
"room": { "id": "ckovh15xa104955sj6r2tqaw1c", "name": "38683b87f2664" }
|
"room": { "id": "ckovh15xa104955sj6r2tqaw1c", "name": "38683b87f2664" }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
env.execute_tokio_future(
|
||||||
ctx.env.execute_tokio_future(
|
|
||||||
async move { Ok(serde_json::to_string(&data).unwrap()) },
|
async move { Ok(serde_json::to_string(&data).unwrap()) },
|
||||||
|env, response| {
|
|env, res| {
|
||||||
env.adjust_external_memory(response.len() as i64)?;
|
env.adjust_external_memory(res.len() as i64)?;
|
||||||
env.create_string_from_std(response)
|
env.create_string_from_std(res)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[js_function(1)]
|
#[napi]
|
||||||
fn from_js(ctx: napi::CallContext) -> napi::Result<napi::JsString> {
|
pub fn from_js(env: Env, input_object: Object) -> napi::Result<String> {
|
||||||
let input_object = ctx.get::<napi::JsObject>(0)?;
|
let a: Welcome = env.from_js_value(&input_object)?;
|
||||||
let a: Welcome = ctx.env.from_js_value(&input_object)?;
|
Ok(serde_json::to_string(&a)?)
|
||||||
ctx.env.create_string_from_std(serde_json::to_string(&a)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[module_exports]
|
pub struct ChildHolder {
|
||||||
fn init(mut exports: napi::JsObject) -> napi::Result<()> {
|
inner: &'static MemoryHolder,
|
||||||
exports.create_named_method("testAsync", test_async)?;
|
}
|
||||||
exports.create_named_method("convertFromJS", from_js)?;
|
|
||||||
Ok(())
|
impl ChildHolder {
|
||||||
|
fn count(&self) -> usize {
|
||||||
|
self.inner.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub struct MemoryHolder(Vec<u8>);
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
impl MemoryHolder {
|
||||||
|
#[napi(constructor)]
|
||||||
|
pub fn new(mut env: Env, len: u32) -> Result<Self> {
|
||||||
|
env.adjust_external_memory(len as i64)?;
|
||||||
|
Ok(Self(vec![42; len as usize]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn create_reference(
|
||||||
|
&self,
|
||||||
|
env: Env,
|
||||||
|
holder_ref: Reference<MemoryHolder>,
|
||||||
|
) -> Result<ChildReference> {
|
||||||
|
let child_holder =
|
||||||
|
holder_ref.share_with(env, |holder_ref| Ok(ChildHolder { inner: holder_ref }))?;
|
||||||
|
Ok(ChildReference(child_holder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub struct ChildReference(SharedReference<MemoryHolder, ChildHolder>);
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
|
||||||
|
impl ChildReference {
|
||||||
|
#[napi]
|
||||||
|
pub fn count(&self) -> u32 {
|
||||||
|
self.0.count() as u32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export async function createSuite(testFile, maxMemoryUsage) {
|
||||||
|
|
||||||
const container = await client.createContainer({
|
const container = await client.createContainer({
|
||||||
Image: 'node:lts-slim',
|
Image: 'node:lts-slim',
|
||||||
Cmd: ['/bin/bash', '-c', `node memory-testing/${testFile}.js`],
|
Cmd: ['/bin/bash', '-c', `node --expose-gc memory-testing/${testFile}.mjs`],
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
Tty: true,
|
Tty: true,
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
const displayMemoryUsageFromNode = require('./util')
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
|
import { displayMemoryUsageFromNode } from './util.mjs'
|
||||||
|
|
||||||
const initialMemoryUsage = process.memoryUsage()
|
const initialMemoryUsage = process.memoryUsage()
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
|
||||||
const api = require(`./index.node`)
|
const api = require(`./index.node`)
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
|
@ -1,8 +1,8 @@
|
||||||
const { whiteBright, red, green, gray } = require('colorette')
|
import { whiteBright, red, green, gray } from 'colorette'
|
||||||
const prettyBytes = require('pretty-bytes')
|
import prettyBytes from 'pretty-bytes'
|
||||||
const { table } = require('table')
|
import { table } from 'table'
|
||||||
|
|
||||||
module.exports = function displayMemoryUsageFromNode(initialMemoryUsage) {
|
export function displayMemoryUsageFromNode(initialMemoryUsage) {
|
||||||
const finalMemoryUsage = process.memoryUsage()
|
const finalMemoryUsage = process.memoryUsage()
|
||||||
const titles = Object.keys(initialMemoryUsage).map((k) => whiteBright(k))
|
const titles = Object.keys(initialMemoryUsage).map((k) => whiteBright(k))
|
||||||
const tableData = [titles]
|
const tableData = [titles]
|
Loading…
Reference in a new issue