Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance regression suite #1093

Merged
merged 9 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:

- name: Generate coverage report
if: matrix.os == 'ubuntu-latest' && matrix.rust-toolchain == 'stable'
run: cargo llvm-cov report --ignore-filename-regex test --codecov --output-path target/codecov.json
run: cargo llvm-cov report --codecov --output-path target/codecov.json

- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.rust-toolchain == 'stable'
Expand Down
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ resolver = "2"
members = [
"crates/*",
"test/*",
"bench",
]
4 changes: 4 additions & 0 deletions bench/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
index.node
npm-debug.log*
cargo.log
cross.log
16 changes: 16 additions & 0 deletions bench/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "bench"
version = "0.1.0"
description = "Neon performance regression suite"
authors = ["David Herman <david.herman@gmail.com>"]
license = "MIT"
edition = "2021"
exclude = ["index.node"]

[lib]
crate-type = ["cdylib"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
neon = { path = "../crates/neon" }
17 changes: 17 additions & 0 deletions bench/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# bench: Neon performance regression suite

## Building bench

To run the build, run:

```sh
$ npm run build
```

## Running the benchmarks

To run the benchmarks, run:

```sh
$ npm run benchmark
```
68 changes: 68 additions & 0 deletions bench/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { Suite, jsonReport } = require("bench-node");
const addon = require("./index.node");

function median(values) {
const sorted = [...values].sort((a, b) => a - b);
const n = sorted.length;
return n % 2 === 0
? (sorted[n / 2 - 1] + sorted[n / 2]) / 2
: sorted[Math.floor(n / 2)];
}

// A custom reporter for the bencher.dev benchmarking platform.
// Format: https://bencher.dev/docs/reference/bencher-metric-format/
//
// The reporter provides two measures for each benchmark:
// - "throughput": The number of operations per second.
// - "latency": The time taken to perform an operation, in ns.
// * "value": The median value of all samples.
// * "lower_value": The minimum value of all samples.
// * "upper_value": The maximum value of all samples.
function reportBencherDev(results) {
const bmf = Object.create(null);
for (const result of results) {
bmf[result.name] = {
throughput: {
value: result.opsSec,
},
latency: {
value: median(result.histogram.sampleData),
lower_value: result.histogram.min,
upper_value: result.histogram.max,
},
};
}
console.log(JSON.stringify(bmf, null, 2));
}

const suite = new Suite({ reporter: reportBencherDev });

suite.add("hello-world", () => {
addon.hello();
});

suite.add("manually-exported-noop", () => {
addon.manualNoop();
});

suite.add("auto-exported-noop", () => {
addon.exportNoop();
});

function triple(s, n, b) {
return [s, n, b];
}

suite.add("JsFunction::call", () => {
addon.callCallbackWithCall(triple);
});

suite.add("JsFunction::call_with", () => {
addon.callCallbackWithCallWith(triple);
});

suite.add("JsFunction::bind", () => {
addon.callCallbackWithBind(triple);
});

suite.run();
27 changes: 27 additions & 0 deletions bench/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "bench",
"private": true,
"description": "Neon performance regression suite",
"main": "index.js",
"scripts": {
"benchmark": "node --allow-natives-syntax index.js",
"cargo-build": "cargo build --message-format=json-render-diagnostics > cargo.log",
"postcargo-build": "neon dist < cargo.log",
"build": "npm run cargo-build -- --release"
},
"author": "David Herman <david.herman@gmail.com>",
"devDependencies": {
"@neon-rs/cli": "0.1.82"
},
"repository": {
"type": "git",
"url": "git+https://github.com/neon-bindings/neon.git"
},
"bugs": {
"url": "https://github.com/neon-bindings/neon/issues"
},
"homepage": "https://github.com/neon-bindings/neon#readme",
"dependencies": {
"bench-node": "^0.5.4"
}
}
57 changes: 57 additions & 0 deletions bench/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use neon::prelude::*;

#[neon::export]
fn export_noop() {}

fn manual_noop(mut cx: FunctionContext) -> JsResult<JsUndefined> {
Ok(cx.undefined())
}

fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
Ok(cx.string("hello node"))
}

fn call_callback_with_call(mut cx: FunctionContext) -> JsResult<JsValue> {
let f = cx.argument::<JsFunction>(0)?;
let s = cx.string("hello node");
let n = cx.number(17.0);
let b = cx.boolean(true);
let this = cx.null();
let args = vec![s.upcast(), n.upcast(), b.upcast()];
f.call(&mut cx, this, args)
}

fn call_callback_with_call_with(mut cx: FunctionContext) -> JsResult<JsValue> {
let f = cx.argument::<JsFunction>(0)?;
f.call_with(&cx)
.this(cx.null())
.arg(cx.string("hello node"))
.arg(cx.number(17.0))
.arg(cx.boolean(true))
.apply(&mut cx)
}

fn call_callback_with_bind(mut cx: FunctionContext) -> JsResult<JsValue> {
let f = cx.argument::<JsFunction>(0)?;
let this = cx.null();
f.bind(&mut cx)
.this(this)?
.arg("hello node")?
.arg(17.0)?
.arg(true)?
.call()
}

#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
// Export all macro-registered exports
neon::registered().export(&mut cx)?;

cx.export_function("hello", hello)?;
cx.export_function("manualNoop", manual_noop)?;
cx.export_function("callCallbackWithCall", call_callback_with_call)?;
cx.export_function("callCallbackWithCallWith", call_callback_with_call_with)?;
cx.export_function("callCallbackWithBind", call_callback_with_bind)?;

Ok(())
}
3 changes: 3 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ignore:
- "bench"
- "test"
Loading