Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

1
benchmark/napi/buffer/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,85 @@
#include <node_api.h>
#include <stdio.h>
#include <stdlib.h>
#define NODE_API_CALL(call) \
do { \
napi_status status = call; \
if (status != napi_ok) { \
fprintf(stderr, #call " failed: %d\n", status); \
abort(); \
} \
} while (0)
#define ABORT_IF_FALSE(condition) \
if (!(condition)) { \
fprintf(stderr, #condition " failed\n"); \
abort(); \
}
static void Finalize(node_api_basic_env env, void* data, void* hint) {
delete[] static_cast<uint8_t*>(data);
}
static napi_value CreateExternalBuffer(napi_env env, napi_callback_info info) {
napi_value argv[2], undefined, start, end;
size_t argc = 2;
int32_t n = 0;
napi_valuetype val_type = napi_undefined;
// Validate params and retrieve start and end function.
NODE_API_CALL(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
ABORT_IF_FALSE(argc == 2);
NODE_API_CALL(napi_typeof(env, argv[0], &val_type));
ABORT_IF_FALSE(val_type == napi_object);
NODE_API_CALL(napi_typeof(env, argv[1], &val_type));
ABORT_IF_FALSE(val_type == napi_number);
NODE_API_CALL(napi_get_named_property(env, argv[0], "start", &start));
NODE_API_CALL(napi_typeof(env, start, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_named_property(env, argv[0], "end", &end));
NODE_API_CALL(napi_typeof(env, end, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_value_int32(env, argv[1], &n));
NODE_API_CALL(napi_get_undefined(env, &undefined));
constexpr uint32_t kBufferLen = 32;
// Start the benchmark.
napi_call_function(env, argv[0], start, 0, nullptr, nullptr);
for (int32_t idx = 0; idx < n; idx++) {
napi_handle_scope scope;
uint8_t* buffer = new uint8_t[kBufferLen];
napi_value jsbuffer;
NODE_API_CALL(napi_open_handle_scope(env, &scope));
NODE_API_CALL(napi_create_external_buffer(
env, kBufferLen, buffer, Finalize, nullptr, &jsbuffer));
NODE_API_CALL(napi_close_handle_scope(env, scope));
}
// Conclude the benchmark.
napi_value end_argv[] = {argv[1]};
NODE_API_CALL(napi_call_function(env, argv[0], end, 1, end_argv, nullptr));
return undefined;
}
NAPI_MODULE_INIT() {
napi_property_descriptor props[] = {
{"createExternalBuffer",
nullptr,
CreateExternalBuffer,
nullptr,
nullptr,
nullptr,
static_cast<napi_property_attributes>(napi_writable | napi_configurable |
napi_enumerable),
nullptr},
};
NODE_API_CALL(napi_define_properties(
env, exports, sizeof(props) / sizeof(*props), props));
return exports;
}

View File

@ -0,0 +1,18 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ],
'defines': [
'NAPI_EXPERIMENTAL'
]
},
{
'target_name': 'binding_node_api_v8',
'sources': [ 'binding.cc' ],
'defines': [
'NAPI_VERSION=8'
]
}
]
}

View File

@ -0,0 +1,14 @@
'use strict';
const common = require('../../common.js');
const bench = common.createBenchmark(main, {
n: [5e6],
addon: ['binding', 'binding_node_api_v8'],
implem: ['createExternalBuffer'],
});
function main({ n, implem, addon }) {
const binding = require(`./build/${common.buildType}/${addon}`);
binding[implem](bench, n);
}

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,104 @@
#include <node_api.h>
#include <stdio.h>
#include <stdlib.h>
#define NODE_API_CALL(call) \
do { \
napi_status status = call; \
if (status != napi_ok) { \
fprintf(stderr, #call " failed: %d\n", status); \
abort(); \
} \
} while (0)
#define ABORT_IF_FALSE(condition) \
if (!(condition)) { \
fprintf(stderr, #condition " failed\n"); \
abort(); \
}
static napi_value Runner(napi_env env,
napi_callback_info info,
napi_property_attributes attr) {
napi_value argv[2], undefined, js_array_length, start, end;
size_t argc = 2;
napi_valuetype val_type = napi_undefined;
bool is_array = false;
uint32_t array_length = 0;
napi_value* native_array;
// Validate params and retrieve start and end function.
NODE_API_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
ABORT_IF_FALSE(argc == 2);
NODE_API_CALL(napi_typeof(env, argv[0], &val_type));
ABORT_IF_FALSE(val_type == napi_object);
NODE_API_CALL(napi_is_array(env, argv[1], &is_array));
ABORT_IF_FALSE(is_array);
NODE_API_CALL(napi_get_array_length(env, argv[1], &array_length));
NODE_API_CALL(napi_get_named_property(env, argv[0], "start", &start));
NODE_API_CALL(napi_typeof(env, start, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_named_property(env, argv[0], "end", &end));
NODE_API_CALL(napi_typeof(env, end, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_create_uint32(env, array_length, &js_array_length));
// Copy objects into a native array.
native_array = malloc(array_length * sizeof(*native_array));
for (uint32_t idx = 0; idx < array_length; idx++) {
NODE_API_CALL(napi_get_element(env, argv[1], idx, &native_array[idx]));
}
const napi_property_descriptor desc = {
"prop", NULL, NULL, NULL, NULL, js_array_length, attr, NULL};
// Start the benchmark.
napi_call_function(env, argv[0], start, 0, NULL, NULL);
for (uint32_t idx = 0; idx < array_length; idx++) {
NODE_API_CALL(napi_define_properties(env, native_array[idx], 1, &desc));
}
// Conclude the benchmark.
NODE_API_CALL(
napi_call_function(env, argv[0], end, 1, &js_array_length, NULL));
free(native_array);
return undefined;
}
static napi_value RunFastPath(napi_env env, napi_callback_info info) {
return Runner(env, info, napi_writable | napi_enumerable | napi_configurable);
}
static napi_value RunSlowPath(napi_env env, napi_callback_info info) {
return Runner(env, info, napi_writable | napi_enumerable);
}
NAPI_MODULE_INIT() {
napi_property_descriptor props[] = {
{"runFastPath",
NULL,
RunFastPath,
NULL,
NULL,
NULL,
napi_writable | napi_configurable | napi_enumerable,
NULL},
{"runSlowPath",
NULL,
RunSlowPath,
NULL,
NULL,
NULL,
napi_writable | napi_configurable | napi_enumerable,
NULL},
};
NODE_API_CALL(napi_define_properties(
env, exports, sizeof(props) / sizeof(*props), props));
return exports;
}

View File

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.c' ]
}
]
}

View File

@ -0,0 +1,15 @@
'use strict';
const common = require('../../common.js');
const binding = require(`./build/${common.buildType}/binding`);
const bench = common.createBenchmark(main, {
n: [5e6],
implem: ['runFastPath', 'runSlowPath'],
});
function main({ n, implem }) {
const objs = Array(n).fill(null).map((item) => new Object());
binding[implem](bench, objs);
}

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,145 @@
#include <v8.h>
#include <node.h>
#include <assert.h>
using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Uint32;
using v8::Value;
void CallWithString(const FunctionCallbackInfo<Value>& args) {
assert(args.Length() == 1 && args[0]->IsString());
if (args.Length() == 1 && args[0]->IsString()) {
Local<String> str = args[0].As<String>();
const size_t length = str->Utf8LengthV2(args.GetIsolate()) + 1;
char* buf = new char[length];
str->WriteUtf8(args.GetIsolate(), buf, length);
delete[] buf;
}
}
void CallWithArray(const FunctionCallbackInfo<Value>& args) {
assert(args.Length() == 1 && args[0]->IsArray());
if (args.Length() == 1 && args[0]->IsArray()) {
const Local<Array> array = args[0].As<Array>();
uint32_t length = array->Length();
for (uint32_t i = 0; i < length; i++) {
Local<Value> v;
v = array->Get(args.GetIsolate()->GetCurrentContext(),
i).ToLocalChecked();
}
}
}
void CallWithNumber(const FunctionCallbackInfo<Value>& args) {
assert(args.Length() == 1 && args[0]->IsNumber());
if (args.Length() == 1 && args[0]->IsNumber()) {
args[0].As<Number>()->Value();
}
}
void CallWithObject(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
assert(args.Length() == 1 && args[0]->IsObject());
if (args.Length() == 1 && args[0]->IsObject()) {
Local<Object> obj = args[0].As<Object>();
MaybeLocal<String> map_key = String::NewFromUtf8(isolate,
"map", v8::NewStringType::kNormal);
assert(!map_key.IsEmpty());
MaybeLocal<Value> map_maybe = obj->Get(context,
map_key.ToLocalChecked());
assert(!map_maybe.IsEmpty());
Local<Value> map;
map = map_maybe.ToLocalChecked();
MaybeLocal<String> operand_key = String::NewFromUtf8(isolate,
"operand", v8::NewStringType::kNormal);
assert(!operand_key.IsEmpty());
MaybeLocal<Value> operand_maybe = obj->Get(context,
operand_key.ToLocalChecked());
assert(!operand_maybe.IsEmpty());
Local<Value> operand;
operand = operand_maybe.ToLocalChecked();
MaybeLocal<String> data_key = String::NewFromUtf8(isolate,
"data", v8::NewStringType::kNormal);
assert(!data_key.IsEmpty());
MaybeLocal<Value> data_maybe = obj->Get(context,
data_key.ToLocalChecked());
assert(!data_maybe.IsEmpty());
Local<Value> data;
data = data_maybe.ToLocalChecked();
MaybeLocal<String> reduce_key = String::NewFromUtf8(isolate,
"reduce", v8::NewStringType::kNormal);
assert(!reduce_key.IsEmpty());
MaybeLocal<Value> reduce_maybe = obj->Get(context,
reduce_key.ToLocalChecked());
assert(!reduce_maybe.IsEmpty());
Local<Value> reduce;
reduce = reduce_maybe.ToLocalChecked();
}
}
void CallWithTypedarray(const FunctionCallbackInfo<Value>& args) {
assert(args.Length() == 1 && args[0]->IsArrayBufferView());
if (args.Length() == 1 && args[0]->IsArrayBufferView()) {
assert(args[0]->IsArrayBufferView());
Local<ArrayBufferView> view = args[0].As<ArrayBufferView>();
const size_t byte_offset = view->ByteOffset();
const size_t byte_length = view->ByteLength();
assert(byte_length > 0);
assert(view->HasBuffer());
Local<ArrayBuffer> buffer = view->Buffer();
std::shared_ptr<BackingStore> bs = buffer->GetBackingStore();
const uint32_t* data = reinterpret_cast<uint32_t*>(
static_cast<uint8_t*>(bs->Data()) + byte_offset);
assert(data);
}
}
void CallWithArguments(const FunctionCallbackInfo<Value>& args) {
assert(args.Length() > 1 && args[0]->IsNumber());
if (args.Length() > 1 && args[0]->IsNumber()) {
int32_t loop = args[0].As<Uint32>()->Value();
for (int32_t i = 1; i < loop; ++i) {
assert(i < args.Length());
assert(args[i]->IsUint32());
args[i].As<Uint32>()->Value();
}
}
}
void Initialize(Local<Object> target,
Local<Value> module,
void* data) {
NODE_SET_METHOD(target, "callWithString", CallWithString);
NODE_SET_METHOD(target, "callWithLongString", CallWithString);
NODE_SET_METHOD(target, "callWithArray", CallWithArray);
NODE_SET_METHOD(target, "callWithLargeArray", CallWithArray);
NODE_SET_METHOD(target, "callWithHugeArray", CallWithArray);
NODE_SET_METHOD(target, "callWithNumber", CallWithNumber);
NODE_SET_METHOD(target, "callWithObject", CallWithObject);
NODE_SET_METHOD(target, "callWithTypedarray", CallWithTypedarray);
NODE_SET_METHOD(target, "callWith10Numbers", CallWithArguments);
NODE_SET_METHOD(target, "callWith100Numbers", CallWithArguments);
NODE_SET_METHOD(target, "callWith1000Numbers", CallWithArguments);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

View File

@ -0,0 +1,12 @@
{
'targets': [
{
'target_name': 'napi_binding',
'sources': [ 'napi_binding.c' ]
},
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}

View File

@ -0,0 +1,97 @@
// Show the difference between calling a V8 binding C++ function
// relative to a comparable N-API C++ function,
// in various types/numbers of arguments.
// Reports n of calls per second.
'use strict';
const common = require('../../common.js');
let v8;
let napi;
try {
v8 = require(`./build/${common.buildType}/binding`);
} catch {
console.error(`${__filename}: V8 Binding failed to load`);
process.exit(0);
}
try {
napi = require(`./build/${common.buildType}/napi_binding`);
} catch {
console.error(`${__filename}: NAPI-Binding failed to load`);
process.exit(0);
}
const argsTypes = ['String', 'Number', 'Object', 'Array', 'Typedarray',
'10Numbers', '100Numbers', '1000Numbers'];
const generateArgs = (argType) => {
let args = [];
if (argType === 'String') {
args.push('The quick brown fox jumps over the lazy dog');
} else if (argType === 'LongString') {
args.push(Buffer.alloc(32768, '42').toString());
} else if (argType === 'Number') {
args.push(Math.floor(314158964 * Math.random()));
} else if (argType === 'Object') {
args.push({
map: 'add',
operand: 10,
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
reduce: 'add',
});
} else if (argType === 'Array') {
const arr = [];
for (let i = 0; i < 50; ++i) {
arr.push(Math.random() * 10e9);
}
args.push(arr);
} else if (argType === 'Typedarray') {
const arr = new Uint32Array(1000);
for (let i = 0; i < 1000; ++i) {
arr[i] = Math.random() * 4294967296;
}
args.push(arr);
} else if (argType === '10Numbers') {
args.push(10);
for (let i = 0; i < 9; ++i) {
args = [...args, ...generateArgs('Number')];
}
} else if (argType === '100Numbers') {
args.push(100);
for (let i = 0; i < 99; ++i) {
args = [...args, ...generateArgs('Number')];
}
} else if (argType === '1000Numbers') {
args.push(1000);
for (let i = 0; i < 999; ++i) {
args = [...args, ...generateArgs('Number')];
}
}
return args;
};
const bench = common.createBenchmark(main, {
type: argsTypes,
engine: ['v8', 'napi'],
n: [1, 1e1, 1e2, 1e3, 1e4, 1e5],
});
function main({ n, engine, type }) {
const bindings = engine === 'v8' ? v8 : napi;
const methodName = 'callWith' + type;
const fn = bindings[methodName];
if (fn) {
const args = generateArgs(type);
bench.start();
for (let i = 0; i < n; i++) {
fn.apply(null, args);
}
bench.end(n);
}
}

View File

@ -0,0 +1,231 @@
#include <node_api.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static napi_value CallWithString(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1];
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
napi_valuetype types[1];
status = napi_typeof(env, args[0], types);
assert(status == napi_ok);
assert(types[0] == napi_string);
if (types[0] == napi_string) {
size_t len = 0;
// Get the length
status = napi_get_value_string_utf8(env, args[0], NULL, 0, &len);
assert(status == napi_ok);
char* buf = (char*)malloc(len + 1);
status = napi_get_value_string_utf8(env, args[0], buf, len + 1, &len);
assert(status == napi_ok);
free(buf);
}
return NULL;
}
static napi_value CallWithArray(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1];
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
napi_value array = args[0];
bool is_array = false;
status = napi_is_array(env, array, &is_array);
assert(status == napi_ok);
assert(is_array);
if (is_array) {
uint32_t length;
status = napi_get_array_length(env, array, &length);
assert(status == napi_ok);
uint32_t i;
for (i = 0; i < length; ++i) {
napi_value v;
status = napi_get_element(env, array, i, &v);
assert(status == napi_ok);
}
}
return NULL;
}
static napi_value CallWithNumber(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1];
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
napi_valuetype types[1];
status = napi_typeof(env, args[0], types);
assert(status == napi_ok);
assert(types[0] == napi_number);
if (types[0] == napi_number) {
double value = 0.0;
status = napi_get_value_double(env, args[0], &value);
assert(status == napi_ok);
}
return NULL;
}
static napi_value CallWithObject(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1];
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
napi_valuetype types[1];
status = napi_typeof(env, args[0], types);
assert(status == napi_ok);
assert(argc == 1 && types[0] == napi_object);
if (argc == 1 && types[0] == napi_object) {
napi_value value;
status = napi_get_named_property(env, args[0], "map", &value);
assert(status == napi_ok);
status = napi_get_named_property(env, args[0], "operand", &value);
assert(status == napi_ok);
status = napi_get_named_property(env, args[0], "data", &value);
assert(status == napi_ok);
status = napi_get_named_property(env, args[0], "reduce", &value);
assert(status == napi_ok);
}
return NULL;
}
static napi_value CallWithTypedarray(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1];
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
bool is_typedarray = false;
status = napi_is_typedarray(env, args[0], &is_typedarray);
assert(status == napi_ok);
assert(is_typedarray);
if (is_typedarray) {
napi_typedarray_type type;
napi_value input_buffer;
size_t byte_offset = 0;
size_t length = 0;
status = napi_get_typedarray_info(env, args[0], &type, &length,
NULL, &input_buffer, &byte_offset);
assert(status == napi_ok);
assert(length > 0);
void* data = NULL;
size_t byte_length = 0;
status = napi_get_arraybuffer_info(env,
input_buffer, &data, &byte_length);
assert(status == napi_ok);
uint32_t* input_integers = (uint32_t*)((uint8_t*)(data) + byte_offset);
assert(input_integers);
}
return NULL;
}
static napi_value CallWithArguments(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 1;
napi_value args[1000];
// Get the length
status = napi_get_cb_info(env, info, &argc, NULL, NULL, NULL);
assert(status == napi_ok);
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
assert(status == napi_ok);
assert(argc <= 1000);
napi_valuetype types[1];
status = napi_typeof(env, args[0], types);
assert(status == napi_ok);
assert(argc > 1 && types[0] == napi_number);
if (argc > 1 && types[0] == napi_number) {
uint32_t loop = 0;
status = napi_get_value_uint32(env, args[0], &loop);
assert(status == napi_ok);
uint32_t i;
for (i = 1; i < loop; ++i) {
assert(i < argc);
status = napi_typeof(env, args[i], types);
assert(status == napi_ok);
assert(types[0] == napi_number);
uint32_t value = 0;
status = napi_get_value_uint32(env, args[i], &value);
assert(status == napi_ok);
}
}
return NULL;
}
#define EXPORT_FUNC(env, exports, name, func) \
do { \
napi_status status; \
napi_value js_func; \
status = napi_create_function((env), \
(name), \
NAPI_AUTO_LENGTH, \
(func), \
NULL, \
&js_func); \
assert(status == napi_ok); \
status = napi_set_named_property((env), \
(exports), \
(name), \
js_func); \
assert(status == napi_ok); \
} while (0);
NAPI_MODULE_INIT() {
EXPORT_FUNC(env, exports, "callWithString", CallWithString);
EXPORT_FUNC(env, exports, "callWithLongString", CallWithString);
EXPORT_FUNC(env, exports, "callWithArray", CallWithArray);
EXPORT_FUNC(env, exports, "callWithLargeArray", CallWithArray);
EXPORT_FUNC(env, exports, "callWithHugeArray", CallWithArray);
EXPORT_FUNC(env, exports, "callWithNumber", CallWithNumber);
EXPORT_FUNC(env, exports, "callWithObject", CallWithObject);
EXPORT_FUNC(env, exports, "callWithTypedarray", CallWithTypedarray);
EXPORT_FUNC(env, exports, "callWith10Numbers", CallWithArguments);
EXPORT_FUNC(env, exports, "callWith100Numbers", CallWithArguments);
EXPORT_FUNC(env, exports, "callWith1000Numbers", CallWithArguments);
return exports;
}

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,16 @@
#include <v8.h>
#include <node.h>
static int c = 0;
void Hello(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(c++);
}
void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> module,
void* data) {
NODE_SET_METHOD(target, "hello", Hello);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

View File

@ -0,0 +1,12 @@
{
'targets': [
{
'target_name': 'napi_binding',
'sources': [ 'napi_binding.c' ]
},
{
'target_name': 'binding',
'sources': [ 'binding.cc' ]
}
]
}

View File

@ -0,0 +1,51 @@
// Show the difference between calling a short js function
// relative to a comparable C++ function.
// Reports n of calls per second.
// Note that JS speed goes up, while cxx speed stays about the same.
'use strict';
const assert = require('assert');
const common = require('../../common.js');
// This fails when we try to open with a different version of node,
// which is quite common for benchmarks. so in that case, just
// abort quietly.
let binding;
try {
binding = require(`./build/${common.buildType}/binding`);
} catch {
console.error('misc/function_call.js Binding failed to load');
process.exit(0);
}
const cxx = binding.hello;
let napi_binding;
try {
napi_binding = require(`./build/${common.buildType}/napi_binding`);
} catch {
console.error('misc/function_call/index.js NAPI-Binding failed to load');
process.exit(0);
}
const napi = napi_binding.hello;
let c = 0;
function js() {
return c++;
}
assert(js() === cxx());
const bench = common.createBenchmark(main, {
type: ['js', 'cxx', 'napi'],
n: [1e6, 1e7, 5e7],
});
function main({ n, type }) {
const fn = type === 'cxx' ? cxx : type === 'napi' ? napi : js;
bench.start();
for (let i = 0; i < n; i++) {
fn();
}
bench.end(n);
}

View File

@ -0,0 +1,26 @@
#include <assert.h>
#include <node_api.h>
static int32_t increment = 0;
static napi_value Hello(napi_env env, napi_callback_info info) {
napi_value result;
napi_status status = napi_create_int32(env, increment++, &result);
assert(status == napi_ok);
return result;
}
NAPI_MODULE_INIT() {
napi_value hello;
napi_status status =
napi_create_function(env,
"hello",
NAPI_AUTO_LENGTH,
Hello,
NULL,
&hello);
assert(status == napi_ok);
status = napi_set_named_property(env, exports, "hello", hello);
assert(status == napi_ok);
return exports;
}

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,111 @@
#include <node_api.h>
#include <stdio.h>
#include <stdlib.h>
#define NODE_API_CALL(call) \
do { \
napi_status status = call; \
if (status != napi_ok) { \
fprintf(stderr, #call " failed: %d\n", status); \
abort(); \
} \
} while (0)
#define ABORT_IF_FALSE(condition) \
if (!(condition)) { \
fprintf(stderr, #condition " failed\n"); \
abort(); \
}
static napi_value Runner(napi_env env,
napi_callback_info info,
napi_value property_key) {
napi_value argv[2], undefined, js_array_length, start, end;
size_t argc = 2;
napi_valuetype val_type = napi_undefined;
bool is_array = false;
uint32_t array_length = 0;
napi_value* native_array;
// Validate params and retrieve start and end function.
NODE_API_CALL(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
ABORT_IF_FALSE(argc == 2);
NODE_API_CALL(napi_typeof(env, argv[0], &val_type));
ABORT_IF_FALSE(val_type == napi_object);
NODE_API_CALL(napi_is_array(env, argv[1], &is_array));
ABORT_IF_FALSE(is_array);
NODE_API_CALL(napi_get_array_length(env, argv[1], &array_length));
NODE_API_CALL(napi_get_named_property(env, argv[0], "start", &start));
NODE_API_CALL(napi_typeof(env, start, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_named_property(env, argv[0], "end", &end));
NODE_API_CALL(napi_typeof(env, end, &val_type));
ABORT_IF_FALSE(val_type == napi_function);
NODE_API_CALL(napi_get_undefined(env, &undefined));
NODE_API_CALL(napi_create_uint32(env, array_length, &js_array_length));
// Copy objects into a native array.
native_array =
static_cast<napi_value*>(malloc(array_length * sizeof(napi_value)));
for (uint32_t idx = 0; idx < array_length; idx++) {
NODE_API_CALL(napi_get_element(env, argv[1], idx, &native_array[idx]));
}
// Start the benchmark.
napi_call_function(env, argv[0], start, 0, nullptr, nullptr);
for (uint32_t idx = 0; idx < array_length; idx++) {
NODE_API_CALL(
napi_set_property(env, native_array[idx], property_key, undefined));
}
// Conclude the benchmark.
NODE_API_CALL(
napi_call_function(env, argv[0], end, 1, &js_array_length, nullptr));
free(native_array);
return undefined;
}
static napi_value RunPropertyKey(napi_env env, napi_callback_info info) {
napi_value property_key;
NODE_API_CALL(node_api_create_property_key_utf16(
env, u"prop", NAPI_AUTO_LENGTH, &property_key));
return Runner(env, info, property_key);
}
static napi_value RunNormalString(napi_env env, napi_callback_info info) {
napi_value property_key;
NODE_API_CALL(
napi_create_string_utf16(env, u"prop", NAPI_AUTO_LENGTH, &property_key));
return Runner(env, info, property_key);
}
NAPI_MODULE_INIT() {
napi_property_descriptor props[] = {
{"RunPropertyKey",
nullptr,
RunPropertyKey,
nullptr,
nullptr,
nullptr,
static_cast<napi_property_attributes>(napi_writable | napi_configurable |
napi_enumerable),
nullptr},
{"RunNormalString",
nullptr,
RunNormalString,
nullptr,
nullptr,
nullptr,
static_cast<napi_property_attributes>(napi_writable | napi_configurable |
napi_enumerable),
nullptr},
};
NODE_API_CALL(napi_define_properties(
env, exports, sizeof(props) / sizeof(*props), props));
return exports;
}

View File

@ -0,0 +1,9 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ],
'defines': [ 'NAPI_EXPERIMENTAL' ],
}
]
}

View File

@ -0,0 +1,15 @@
'use strict';
const common = require('../../common.js');
const binding = require(`./build/${common.buildType}/binding`);
const bench = common.createBenchmark(main, {
n: [5e6],
implem: ['RunPropertyKey', 'RunNormalString'],
});
function main({ n, implem }) {
const objs = Array(n).fill(null).map((item) => new Object());
binding[implem](bench, objs);
}

1
benchmark/napi/ref/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,80 @@
#include <node_api.h>
#include <stdlib.h>
#define NAPI_CALL(env, call) \
do { \
napi_status status = (call); \
if (status != napi_ok) { \
napi_throw_error((env), NULL, #call " failed"); \
return NULL; \
} \
} while (0)
static napi_value
GetCount(napi_env env, napi_callback_info info) {
napi_value result;
size_t* count;
NAPI_CALL(env, napi_get_instance_data(env, (void**)&count));
NAPI_CALL(env, napi_create_uint32(env, *count, &result));
return result;
}
static napi_value
SetCount(napi_env env, napi_callback_info info) {
size_t* count;
NAPI_CALL(env, napi_get_instance_data(env, (void**)&count));
// Set the count to zero irrespective of what is passed into the setter.
*count = 0;
return NULL;
}
static void IncrementCounter(node_api_basic_env env, void* data, void* hint) {
size_t* count = data;
(*count) = (*count) + 1;
}
static napi_value
NewWeak(napi_env env, napi_callback_info info) {
napi_value result;
void* instance_data;
NAPI_CALL(env, napi_create_object(env, &result));
NAPI_CALL(env, napi_get_instance_data(env, &instance_data));
NAPI_CALL(env, napi_add_finalizer(env,
result,
instance_data,
IncrementCounter,
NULL,
NULL));
return result;
}
static void
FreeCount(napi_env env, void* data, void* hint) {
free(data);
}
/* napi_value */
NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) {
napi_property_descriptor props[] = {
{ "count", NULL, NULL, GetCount, SetCount, NULL, napi_enumerable, NULL },
{ "newWeak", NULL, NewWeak, NULL, NULL, NULL, napi_enumerable, NULL }
};
size_t* count = malloc(sizeof(*count));
*count = 0;
NAPI_CALL(env, napi_define_properties(env,
exports,
sizeof(props) / sizeof(*props),
props));
NAPI_CALL(env, napi_set_instance_data(env, count, FreeCount, NULL));
return exports;
}

View File

@ -0,0 +1,10 @@
{
'targets': [
{
'target_name': 'addon',
'sources': [
'addon.c'
]
}
]
}

View File

@ -0,0 +1,19 @@
'use strict';
const common = require('../../common');
const addon = require(`./build/${common.buildType}/addon`);
const bench = common.createBenchmark(main, { n: [1e7] });
function callNewWeak() {
addon.newWeak();
}
function main({ n }) {
addon.count = 0;
bench.start();
new Promise((resolve) => {
(function oneIteration() {
callNewWeak();
setImmediate(() => ((addon.count < n) ? oneIteration() : resolve()));
})();
}).then(() => bench.end(n));
}

1
benchmark/napi/string/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,56 @@
#include <assert.h>
#define NAPI_EXPERIMENTAL
#include <node_api.h>
#define NAPI_CALL(call) \
do { \
napi_status status = call; \
assert(status == napi_ok && #call " failed"); \
} while (0);
#define EXPORT_FUNC(env, exports, name, func) \
do { \
napi_value js_func; \
NAPI_CALL(napi_create_function( \
(env), (name), NAPI_AUTO_LENGTH, (func), NULL, &js_func)); \
NAPI_CALL(napi_set_named_property((env), (exports), (name), js_func)); \
} while (0);
const char* one_byte_string = "The Quick Brown Fox Jumped Over The Lazy Dog.";
const char16_t* two_byte_string =
u"The Quick Brown Fox Jumped Over The Lazy Dog.";
#define DECLARE_BINDING(CapName, lowercase_name, var_name) \
static napi_value CreateString##CapName(napi_env env, \
napi_callback_info info) { \
size_t argc = 4; \
napi_value argv[4]; \
uint32_t n; \
uint32_t index; \
napi_handle_scope scope; \
napi_value js_string; \
\
NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); \
NAPI_CALL(napi_get_value_uint32(env, argv[0], &n)); \
NAPI_CALL(napi_open_handle_scope(env, &scope)); \
NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL)); \
for (index = 0; index < n; index++) { \
NAPI_CALL(napi_create_string_##lowercase_name( \
env, (var_name), NAPI_AUTO_LENGTH, &js_string)); \
} \
NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL)); \
NAPI_CALL(napi_close_handle_scope(env, scope)); \
\
return NULL; \
}
DECLARE_BINDING(Latin1, latin1, one_byte_string)
DECLARE_BINDING(Utf8, utf8, one_byte_string)
DECLARE_BINDING(Utf16, utf16, two_byte_string)
NAPI_MODULE_INIT() {
EXPORT_FUNC(env, exports, "createStringLatin1", CreateStringLatin1);
EXPORT_FUNC(env, exports, "createStringUtf8", CreateStringUtf8);
EXPORT_FUNC(env, exports, "createStringUtf16", CreateStringUtf16);
return exports;
}

View File

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.c' ]
}
]
}

View File

@ -0,0 +1,19 @@
'use strict';
const common = require('../../common.js');
let binding;
try {
binding = require(`./build/${common.buildType}/binding`);
} catch {
console.error(`${__filename}: Binding failed to load`);
process.exit(0);
}
const bench = common.createBenchmark(main, {
n: [1e5, 1e6, 1e7],
stringType: ['Latin1', 'Utf8', 'Utf16'],
});
function main({ n, stringType }) {
binding[`createString${stringType}`](n, bench, bench.start, bench.end);
}

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ '../type-tag/binding.c' ]
}
]
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../../common.js');
let binding;
try {
binding = require(`./build/${common.buildType}/binding`);
} catch {
console.error(`${__filename}: Binding failed to load`);
process.exit(0);
}
const bench = common.createBenchmark(main, {
n: [1e5, 1e6, 1e7],
});
function main({ n }) {
binding.checkObjectTag(n, bench, bench.start, bench.end);
}

1
benchmark/napi/type-tag/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,84 @@
#include <assert.h>
#define NAPI_EXPERIMENTAL
#include <node_api.h>
#define NAPI_CALL(call) \
do { \
napi_status status = call; \
assert(status == napi_ok && #call " failed"); \
} while (0);
#define EXPORT_FUNC(env, exports, name, func) \
do { \
napi_value js_func; \
NAPI_CALL(napi_create_function((env), \
(name), \
NAPI_AUTO_LENGTH, \
(func), \
NULL, \
&js_func)); \
NAPI_CALL(napi_set_named_property((env), \
(exports), \
(name), \
js_func)); \
} while (0);
static const napi_type_tag tag = {
0xe7ecbcd5954842f6, 0x9e75161c9bf27282
};
static napi_value TagObject(napi_env env, napi_callback_info info) {
size_t argc = 4;
napi_value argv[4];
uint32_t n;
uint32_t index;
napi_handle_scope scope;
NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
NAPI_CALL(napi_get_value_uint32(env, argv[0], &n));
NAPI_CALL(napi_open_handle_scope(env, &scope));
napi_value objects[n];
for (index = 0; index < n; index++) {
NAPI_CALL(napi_create_object(env, &objects[index]));
}
// Time the object tag creation.
NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL));
for (index = 0; index < n; index++) {
NAPI_CALL(napi_type_tag_object(env, objects[index], &tag));
}
NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL));
NAPI_CALL(napi_close_handle_scope(env, scope));
return NULL;
}
static napi_value CheckObjectTag(napi_env env, napi_callback_info info) {
size_t argc = 4;
napi_value argv[4];
uint32_t n;
uint32_t index;
bool is_of_type;
NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
NAPI_CALL(napi_get_value_uint32(env, argv[0], &n));
napi_value object;
NAPI_CALL(napi_create_object(env, &object));
NAPI_CALL(napi_type_tag_object(env, object, &tag));
// Time the object tag checking.
NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL));
for (index = 0; index < n; index++) {
NAPI_CALL(napi_check_object_type_tag(env, object, &tag, &is_of_type));
assert(is_of_type && " type mismatch");
}
NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL));
return NULL;
}
NAPI_MODULE_INIT() {
EXPORT_FUNC(env, exports, "tagObject", TagObject);
EXPORT_FUNC(env, exports, "checkObjectTag", CheckObjectTag);
return exports;
}

View File

@ -0,0 +1,8 @@
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.c' ]
}
]
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../../common.js');
let binding;
try {
binding = require(`./build/${common.buildType}/binding`);
} catch {
console.error(`${__filename}: Binding failed to load`);
process.exit(0);
}
const bench = common.createBenchmark(main, {
n: [1e5, 1e6, 1e7],
});
function main({ n }) {
binding.checkObjectTag(n, bench, bench.start, bench.end);
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../../common.js');
let binding;
try {
binding = require(`./build/${common.buildType}/binding`);
} catch {
console.error(`${__filename}: Binding failed to load`);
process.exit(0);
}
const bench = common.createBenchmark(main, {
n: [1e3, 1e4, 1e5],
});
function main({ n }) {
binding.tagObject(n, bench, bench.start, bench.end);
}