test(napi): add memory tests for Reference

This commit is contained in:
LongYinan 2022-04-06 23:00:21 +08:00
parent 6a252c70d2
commit 63a557f6cc
10 changed files with 110 additions and 27 deletions

View file

@ -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))
{
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()) };
finalize();
let delete_reference_status = unsafe { sys::napi_delete_reference(env, ref_val) };

View file

@ -16,7 +16,9 @@ napi = { path = "../crates/napi", features = [
"latin1",
"compat-mode",
] }
napi-derive = { path = "../crates/macro", features = ["compat-mode"] }
napi-derive = { path = "../crates/macro", default-features = false, features = [
"compat-mode",
] }
serde = "1"
serde_bytes = "0.11"
serde_derive = "1"

View file

@ -1,4 +1,5 @@
import { createSuite } from './test-util.mjs'
await createSuite('reference')
await createSuite('tokio-future')
await createSuite('serde')

View file

@ -3,7 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"build": "node ../cli/scripts/index.js build --release"
"build": "node ../cli/scripts/index.js build --release --js false"
},
"dependencies": {
"colorette": "^2.0.16",

View 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++
}

View file

@ -1,7 +1,11 @@
const displayMemoryUsageFromNode = require('./util')
import { createRequire } from 'module'
import { displayMemoryUsageFromNode } from './util.mjs'
const initialMemoryUsage = process.memoryUsage()
const require = createRequire(import.meta.url)
const api = require(`./index.node`)
const data = {
@ -27,7 +31,7 @@ const data = {
let i = 1
// eslint-disable-next-line no-constant-condition
while (true) {
api.convertFromJS(data)
api.fromJs(data)
if (i % 100000 === 0) {
displayMemoryUsageFromNode(initialMemoryUsage)
}

View file

@ -1,3 +1,5 @@
use napi::{bindgen_prelude::*, Env};
#[macro_use]
extern crate napi_derive;
#[macro_use]
@ -34,8 +36,8 @@ pub struct Room {
name: String,
}
#[js_function]
fn test_async(ctx: napi::CallContext) -> napi::Result<napi::JsObject> {
#[napi]
pub fn test_async(env: Env) -> napi::Result<napi::JsObject> {
let data = serde_json::json!({
"findFirstBooking": {
"id": "ckovh15xa104945sj64rdk8oas",
@ -57,26 +59,62 @@ fn test_async(ctx: napi::CallContext) -> napi::Result<napi::JsObject> {
"room": { "id": "ckovh15xa104955sj6r2tqaw1c", "name": "38683b87f2664" }
}
});
ctx.env.execute_tokio_future(
env.execute_tokio_future(
async move { Ok(serde_json::to_string(&data).unwrap()) },
|env, response| {
env.adjust_external_memory(response.len() as i64)?;
env.create_string_from_std(response)
|env, res| {
env.adjust_external_memory(res.len() as i64)?;
env.create_string_from_std(res)
},
)
}
#[js_function(1)]
fn from_js(ctx: napi::CallContext) -> napi::Result<napi::JsString> {
let input_object = ctx.get::<napi::JsObject>(0)?;
let a: Welcome = ctx.env.from_js_value(&input_object)?;
ctx.env.create_string_from_std(serde_json::to_string(&a)?)
#[napi]
pub fn from_js(env: Env, input_object: Object) -> napi::Result<String> {
let a: Welcome = env.from_js_value(&input_object)?;
Ok(serde_json::to_string(&a)?)
}
#[module_exports]
fn init(mut exports: napi::JsObject) -> napi::Result<()> {
exports.create_named_method("testAsync", test_async)?;
exports.create_named_method("convertFromJS", from_js)?;
Ok(())
pub struct ChildHolder {
inner: &'static MemoryHolder,
}
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
}
}

View file

@ -14,7 +14,7 @@ export async function createSuite(testFile, maxMemoryUsage) {
const container = await client.createContainer({
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,
AttachStderr: true,
Tty: true,

View file

@ -1,7 +1,11 @@
const displayMemoryUsageFromNode = require('./util')
import { createRequire } from 'module'
import { displayMemoryUsageFromNode } from './util.mjs'
const initialMemoryUsage = process.memoryUsage()
const require = createRequire(import.meta.url)
const api = require(`./index.node`)
async function main() {

View file

@ -1,8 +1,8 @@
const { whiteBright, red, green, gray } = require('colorette')
const prettyBytes = require('pretty-bytes')
const { table } = require('table')
import { whiteBright, red, green, gray } from 'colorette'
import prettyBytes from 'pretty-bytes'
import { table } from 'table'
module.exports = function displayMemoryUsageFromNode(initialMemoryUsage) {
export function displayMemoryUsageFromNode(initialMemoryUsage) {
const finalMemoryUsage = process.memoryUsage()
const titles = Object.keys(initialMemoryUsage).map((k) => whiteBright(k))
const tableData = [titles]