From 6aa13a1ad9919de5ffcba642385b379b301476f9 Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Wed, 27 Jun 2018 12:42:18 +0800 Subject: [PATCH 1/8] benchmark: add n-api function arguments benchmark suite This benchmark suite is added to measure the performance of n-api function call with various type/number of arguments. The cases in this suite are carefully selected to efficiently show the performance trend. --- Makefile | 9 + benchmark/napi/function_args/.gitignore | 1 + benchmark/napi/function_args/binding.cc | 100 +++++++++ benchmark/napi/function_args/binding.gyp | 12 + benchmark/napi/function_args/index.js | 110 +++++++++ benchmark/napi/function_args/napi_binding.c | 234 ++++++++++++++++++++ 6 files changed, 466 insertions(+) create mode 100644 benchmark/napi/function_args/.gitignore create mode 100644 benchmark/napi/function_args/binding.cc create mode 100644 benchmark/napi/function_args/binding.gyp create mode 100644 benchmark/napi/function_args/index.js create mode 100644 benchmark/napi/function_args/napi_binding.c diff --git a/Makefile b/Makefile index 025cb164c9f732..09e95eeeb5051b 100644 --- a/Makefile +++ b/Makefile @@ -283,6 +283,15 @@ benchmark/napi/function_call/build/Release/binding.node: all \ --directory="$(shell pwd)/benchmark/napi/function_call" \ --nodedir="$(shell pwd)" +benchmark/napi/function_args/build/Release/binding.node: all \ + benchmark/napi/function_args/napi_binding.c \ + benchmark/napi/function_args/binding.cc \ + benchmark/napi/function_args/binding.gyp + $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ + --python="$(PYTHON)" \ + --directory="$(shell pwd)/benchmark/napi/function_args" \ + --nodedir="$(shell pwd)" + # Implicitly depends on $(NODE_EXE). We don't depend on it explicitly because # it always triggers a rebuild due to it being a .PHONY rule. See the comment # near the build-addons rule for more background. diff --git a/benchmark/napi/function_args/.gitignore b/benchmark/napi/function_args/.gitignore new file mode 100644 index 00000000000000..567609b1234a9b --- /dev/null +++ b/benchmark/napi/function_args/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc new file mode 100644 index 00000000000000..a9224cad48cdcb --- /dev/null +++ b/benchmark/napi/function_args/binding.cc @@ -0,0 +1,100 @@ +#include +#include +#include + +using v8::Local; +using v8::Value; +using v8::Number; +using v8::String; +using v8::Object; +using v8::Array; +using v8::ArrayBufferView; +using v8::ArrayBuffer; +using v8::FunctionCallbackInfo; + +void CallWithString(const FunctionCallbackInfo& args) { + assert(args.Length() == 1 && args[0]->IsString()); + if (args.Length() == 1 && args[0]->IsString()) { + Local str = args[0].As(); + const int32_t length = str->Utf8Length() + 1; + char* buf = new char[length]; + str->WriteUtf8(buf, length); + delete [] buf; + } +} + +void CallWithArray(const FunctionCallbackInfo& args) { + assert(args.Length() == 1 && args[0]->IsArray()); + if (args.Length() == 1 && args[0]->IsArray()) { + const Local array = args[0].As(); + uint32_t length = array->Length(); + for (uint32_t i = 0; i < length; ++ i) { + Local v = array->Get(i); + } + } +} + +void CallWithNumber(const FunctionCallbackInfo& args) { + assert(args.Length() == 1 && args[0]->IsNumber()); + if (args.Length() == 1 && args[0]->IsNumber()) { + double value = args[0].As()->Value(); + } +} + +void CallWithObject(const FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + + assert(args.Length() == 1 && args[0]->IsObject()); + if (args.Length() == 1 && args[0]->IsObject()) { + Local obj = args[0].As(); + Local map = obj->Get(String::NewFromUtf8(isolate, "map")); + Local operand = obj->Get(String::NewFromUtf8(isolate, "operand")); + Local data = obj->Get(String::NewFromUtf8(isolate, "data")); + Local reduce = obj->Get(String::NewFromUtf8(isolate, "reduce")); + } +} + +void CallWithTypedarray(const FunctionCallbackInfo& args) { + assert(args.Length() == 1 && args[0]->IsArrayBufferView()); + if (args.Length() == 1 && args[0]->IsArrayBufferView()) { + assert(args[0]->IsArrayBufferView()); + Local view = args[0].As(); + size_t byte_offset = view->ByteOffset(); + size_t byte_length = view->ByteLength(); + assert(view->HasBuffer()); + Local buffer = view->Buffer(); + ArrayBuffer::Contents contents = buffer->GetContents(); + uint32_t* data = static_cast(contents.Data()) + byte_offset; + } +} + +void CallWithArguments(const FunctionCallbackInfo& args) { + assert(args.Length() > 1 && args[0]->IsNumber()); + if (args.Length() > 1 && args[0]->IsNumber()) { + uint32_t loop = args[0].As()->Value(); + for (uint32_t i = 1; i < loop; ++i) { + assert(i < args.Length()); + assert(args[i]->IsUint32()); + uint32_t value = args[i].As()->Value(); + } + } +} + +void Initialize(Local target) { + 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) diff --git a/benchmark/napi/function_args/binding.gyp b/benchmark/napi/function_args/binding.gyp new file mode 100644 index 00000000000000..ac122ed1a07962 --- /dev/null +++ b/benchmark/napi/function_args/binding.gyp @@ -0,0 +1,12 @@ +{ + 'targets': [ + { + 'target_name': 'napi_binding', + 'sources': [ 'napi_binding.c' ] + }, + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ] + } + ] +} diff --git a/benchmark/napi/function_args/index.js b/benchmark/napi/function_args/index.js new file mode 100644 index 00000000000000..42b6ca7a6ead9e --- /dev/null +++ b/benchmark/napi/function_args/index.js @@ -0,0 +1,110 @@ +// 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/Release/binding'); +} catch (err) { + // eslint-disable-next-line no-path-concat + console.error(__filename + ': V8 Binding failed to load'); + process.exit(0); +} + +try { + napi = require('./build/Release/napi_binding'); +} catch (err) { + // eslint-disable-next-line no-path-concat + 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 getArgs = (type) => { + return generateArgs(type.split('-')[1]); +}; + +const benchTypes = []; + +argsTypes.forEach((arg) => { + ['v8', 'napi'].forEach((type) => { + benchTypes.push(type + '-' + arg); + }); +}); + +const bench = common.createBenchmark(main, { + type: benchTypes, + n: [1, 1e1, 1e2, 1e3, 1e4, 1e5], +}); + +function main({ n, type }) { + const bindings = type.split('-')[0] === 'v8' ? v8 : napi; + const methodName = 'callWith' + type.split('-')[1]; + const fn = bindings[methodName]; + + if (fn) { + const args = getArgs(type); + + bench.start(); + for (var i = 0; i < n; i++) { + fn.apply(null, args); + } + bench.end(n); + } +} diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c new file mode 100644 index 00000000000000..40a029a0ab3102 --- /dev/null +++ b/benchmark/napi/function_args/napi_binding.c @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include + +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); + + for (uint32_t 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(types[0] == napi_object); + if (types[0] == napi_object) { + napi_value key; + napi_value value; + + status = napi_create_string_utf8(env, "map", strlen("map"), &key); + assert(status == napi_ok); + status = napi_get_property(env, args[0], key, &value); + assert(status == napi_ok); + + status = napi_create_string_utf8(env, "operand", strlen("operand"), &key); + assert(status == napi_ok); + status = napi_get_property(env, args[0], key, &value); + assert(status == napi_ok); + + status = napi_create_string_utf8(env, "data", strlen("data"), &key); + assert(status == napi_ok); + status = napi_get_property(env, args[0], key, &value); + assert(status == napi_ok); + + status = napi_create_string_utf8(env, "reduce", strlen("reduce"), &key); + assert(status == napi_ok); + status = napi_get_property(env, args[0], key, &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); + + 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*)((data) + byte_offset); + } + + 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); + + for (uint32_t 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(name, func) \ + do { \ + napi_value func ## _v; \ + status = napi_create_function(env, \ + name, \ + NAPI_AUTO_LENGTH, \ + func, \ + NULL, \ + &func ## _v); \ + assert(status == napi_ok); \ + status = napi_set_named_property(env, exports, name, func ## _v); \ + assert(status == napi_ok); \ + } while (0); + + +NAPI_MODULE_INIT() { + napi_status status; + + EXPORT_FUNC("callWithString", CallWithString); + EXPORT_FUNC("callWithLongString", CallWithString); + + EXPORT_FUNC("callWithArray", CallWithArray); + EXPORT_FUNC("callWithLargeArray", CallWithArray); + EXPORT_FUNC("callWithHugeArray", CallWithArray); + + EXPORT_FUNC("callWithNumber", CallWithNumber); + + EXPORT_FUNC("callWithObject", CallWithObject); + EXPORT_FUNC("callWithTypedarray", CallWithTypedarray); + + EXPORT_FUNC("callWith10Numbers", CallWithArguments); + EXPORT_FUNC("callWith100Numbers", CallWithArguments); + EXPORT_FUNC("callWith1000Numbers", CallWithArguments); + + return exports; +} From cb758e9061567fe8aecd58360ccb80b907cf0ee1 Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Thu, 28 Jun 2018 10:24:46 +0800 Subject: [PATCH 2/8] Some fine adjustment based on the review comments in https://github.com/nodejs/node/pull/21555 --- benchmark/napi/function_args/binding.cc | 42 ++++++++++++++++++--- benchmark/napi/function_args/napi_binding.c | 21 +++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index a9224cad48cdcb..1f298942cbef69 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -2,7 +2,10 @@ #include #include +using v8::Isolate; +using v8::Context; using v8::Local; +using v8::MaybeLocal; using v8::Value; using v8::Number; using v8::String; @@ -42,15 +45,44 @@ void CallWithNumber(const FunctionCallbackInfo& args) { } void CallWithObject(const FunctionCallbackInfo& args) { - v8::Isolate* isolate = args.GetIsolate(); + Isolate* isolate = args.GetIsolate(); + Local context = isolate->GetCurrentContext(); assert(args.Length() == 1 && args[0]->IsObject()); if (args.Length() == 1 && args[0]->IsObject()) { Local obj = args[0].As(); - Local map = obj->Get(String::NewFromUtf8(isolate, "map")); - Local operand = obj->Get(String::NewFromUtf8(isolate, "operand")); - Local data = obj->Get(String::NewFromUtf8(isolate, "data")); - Local reduce = obj->Get(String::NewFromUtf8(isolate, "reduce")); + + MaybeLocal map_key = String::NewFromUtf8(isolate, + "map", v8::NewStringType::kNormal); + assert(!map_key.IsEmpty()); + MaybeLocal map_maybe = obj->Get(context, + map_key.ToLocalChecked()); + assert(!map_maybe.IsEmpty()); + Local map = map_maybe.ToLocalChecked(); + + MaybeLocal operand_key = String::NewFromUtf8(isolate, + "operand", v8::NewStringType::kNormal); + assert(!operand_key.IsEmpty()); + MaybeLocal operand_maybe = obj->Get(context, + operand_key.ToLocalChecked()); + assert(!operand_maybe.IsEmpty()); + Local operand = operand_maybe.ToLocalChecked(); + + MaybeLocal data_key = String::NewFromUtf8(isolate, + "data", v8::NewStringType::kNormal); + assert(!data_key.IsEmpty()); + MaybeLocal data_maybe = obj->Get(context, + data_key.ToLocalChecked()); + assert(!data_maybe.IsEmpty()); + Local data = data_maybe.ToLocalChecked(); + + MaybeLocal reduce_key = String::NewFromUtf8(isolate, + "reduce", v8::NewStringType::kNormal); + assert(!reduce_key.IsEmpty()); + MaybeLocal reduce_maybe = obj->Get(context, + reduce_key.ToLocalChecked()); + assert(!reduce_maybe.IsEmpty()); + Local reduce = reduce_maybe.ToLocalChecked(); } } diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c index 40a029a0ab3102..de9e160af82f37 100644 --- a/benchmark/napi/function_args/napi_binding.c +++ b/benchmark/napi/function_args/napi_binding.c @@ -94,29 +94,20 @@ static napi_value CallWithObject(napi_env env, napi_callback_info info) { status = napi_typeof(env, args[0], types); assert(status == napi_ok); - assert(types[0] == napi_object); - if (types[0] == napi_object) { - napi_value key; + assert(argc == 1 && types[0] == napi_object); + if (argc == 1 && types[0] == napi_object) { napi_value value; - status = napi_create_string_utf8(env, "map", strlen("map"), &key); - assert(status == napi_ok); - status = napi_get_property(env, args[0], key, &value); + status = napi_get_named_property(env, args[0], "map", &value); assert(status == napi_ok); - status = napi_create_string_utf8(env, "operand", strlen("operand"), &key); - assert(status == napi_ok); - status = napi_get_property(env, args[0], key, &value); + status = napi_get_named_property(env, args[0], "operand", &value); assert(status == napi_ok); - status = napi_create_string_utf8(env, "data", strlen("data"), &key); - assert(status == napi_ok); - status = napi_get_property(env, args[0], key, &value); + status = napi_get_named_property(env, args[0], "data", &value); assert(status == napi_ok); - status = napi_create_string_utf8(env, "reduce", strlen("reduce"), &key); - assert(status == napi_ok); - status = napi_get_property(env, args[0], key, &value); + status = napi_get_named_property(env, args[0], "reduce", &value); assert(status == napi_ok); } From 75e6e422b33184e736e0c225bcbff1aef5d26117 Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Fri, 29 Jun 2018 13:25:29 +0800 Subject: [PATCH 3/8] Fixed wrong calc of typedarray offset (result not in use) --- benchmark/napi/function_args/binding.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index 1f298942cbef69..b04a0ae1e3f347 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -96,7 +96,7 @@ void CallWithTypedarray(const FunctionCallbackInfo& args) { assert(view->HasBuffer()); Local buffer = view->Buffer(); ArrayBuffer::Contents contents = buffer->GetContents(); - uint32_t* data = static_cast(contents.Data()) + byte_offset; + uint32_t* data = static_cast(contents.Data() + byte_offset); } } From 173fa80d6e93633a73b4acbeb95b3bd7e7049c30 Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Mon, 2 Jul 2018 13:55:14 +0800 Subject: [PATCH 4/8] Removing compiler warnings --- benchmark/napi/function_args/binding.cc | 38 +++++++++++++-------- benchmark/napi/function_args/napi_binding.c | 4 ++- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index b04a0ae1e3f347..11eb394a6a98f5 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -32,7 +32,8 @@ void CallWithArray(const FunctionCallbackInfo& args) { const Local array = args[0].As(); uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++ i) { - Local v = array->Get(i); + Local v; + v = array->Get(i); } } } @@ -40,7 +41,7 @@ void CallWithArray(const FunctionCallbackInfo& args) { void CallWithNumber(const FunctionCallbackInfo& args) { assert(args.Length() == 1 && args[0]->IsNumber()); if (args.Length() == 1 && args[0]->IsNumber()) { - double value = args[0].As()->Value(); + args[0].As()->Value(); } } @@ -58,7 +59,8 @@ void CallWithObject(const FunctionCallbackInfo& args) { MaybeLocal map_maybe = obj->Get(context, map_key.ToLocalChecked()); assert(!map_maybe.IsEmpty()); - Local map = map_maybe.ToLocalChecked(); + Local map; + map = map_maybe.ToLocalChecked(); MaybeLocal operand_key = String::NewFromUtf8(isolate, "operand", v8::NewStringType::kNormal); @@ -66,7 +68,8 @@ void CallWithObject(const FunctionCallbackInfo& args) { MaybeLocal operand_maybe = obj->Get(context, operand_key.ToLocalChecked()); assert(!operand_maybe.IsEmpty()); - Local operand = operand_maybe.ToLocalChecked(); + Local operand; + operand = operand_maybe.ToLocalChecked(); MaybeLocal data_key = String::NewFromUtf8(isolate, "data", v8::NewStringType::kNormal); @@ -74,7 +77,8 @@ void CallWithObject(const FunctionCallbackInfo& args) { MaybeLocal data_maybe = obj->Get(context, data_key.ToLocalChecked()); assert(!data_maybe.IsEmpty()); - Local data = data_maybe.ToLocalChecked(); + Local data; + data = data_maybe.ToLocalChecked(); MaybeLocal reduce_key = String::NewFromUtf8(isolate, "reduce", v8::NewStringType::kNormal); @@ -82,7 +86,8 @@ void CallWithObject(const FunctionCallbackInfo& args) { MaybeLocal reduce_maybe = obj->Get(context, reduce_key.ToLocalChecked()); assert(!reduce_maybe.IsEmpty()); - Local reduce = reduce_maybe.ToLocalChecked(); + Local reduce; + reduce = reduce_maybe.ToLocalChecked(); } } @@ -91,23 +96,28 @@ void CallWithTypedarray(const FunctionCallbackInfo& args) { if (args.Length() == 1 && args[0]->IsArrayBufferView()) { assert(args[0]->IsArrayBufferView()); Local view = args[0].As(); - size_t byte_offset = view->ByteOffset(); - size_t byte_length = view->ByteLength(); + const size_t byte_offset = view->ByteOffset(); + const size_t byte_length = view->ByteLength(); + assert(byte_length > 0); assert(view->HasBuffer()); - Local buffer = view->Buffer(); - ArrayBuffer::Contents contents = buffer->GetContents(); - uint32_t* data = static_cast(contents.Data() + byte_offset); + Local buffer; + buffer = view->Buffer(); + ArrayBuffer::Contents contents; + contents = buffer->GetContents(); + const uint32_t* data = reinterpret_cast( + static_cast(contents.Data()) + byte_offset); + assert(data); } } void CallWithArguments(const FunctionCallbackInfo& args) { assert(args.Length() > 1 && args[0]->IsNumber()); if (args.Length() > 1 && args[0]->IsNumber()) { - uint32_t loop = args[0].As()->Value(); - for (uint32_t i = 1; i < loop; ++i) { + int32_t loop = args[0].As()->Value(); + for (int32_t i = 1; i < loop; ++i) { assert(i < args.Length()); assert(args[i]->IsUint32()); - uint32_t value = args[i].As()->Value(); + args[i].As()->Value(); } } } diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c index de9e160af82f37..643ab313093b89 100644 --- a/benchmark/napi/function_args/napi_binding.c +++ b/benchmark/napi/function_args/napi_binding.c @@ -135,6 +135,7 @@ static napi_value CallWithTypedarray(napi_env env, napi_callback_info info) { 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; @@ -142,7 +143,8 @@ static napi_value CallWithTypedarray(napi_env env, napi_callback_info info) { input_buffer, &data, &byte_length); assert(status == napi_ok); - uint32_t* input_integers = (uint32_t*)((data) + byte_offset); + uint32_t* input_integers = (uint32_t*)((uint8_t*)(data) + byte_offset); + assert(input_integers); } return NULL; From 10f3fc55cc01854d6d9544e56564313065de15fd Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Mon, 2 Jul 2018 14:02:56 +0800 Subject: [PATCH 5/8] Use benchmark suite feature to match every engines with every args-types --- benchmark/napi/function_args/index.js | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/benchmark/napi/function_args/index.js b/benchmark/napi/function_args/index.js index 42b6ca7a6ead9e..c8f281a3429fde 100644 --- a/benchmark/napi/function_args/index.js +++ b/benchmark/napi/function_args/index.js @@ -76,30 +76,19 @@ const generateArgs = (argType) => { return args; }; -const getArgs = (type) => { - return generateArgs(type.split('-')[1]); -}; - -const benchTypes = []; - -argsTypes.forEach((arg) => { - ['v8', 'napi'].forEach((type) => { - benchTypes.push(type + '-' + arg); - }); -}); - const bench = common.createBenchmark(main, { - type: benchTypes, + type: argsTypes, + engine: ['v8', 'napi'], n: [1, 1e1, 1e2, 1e3, 1e4, 1e5], }); -function main({ n, type }) { - const bindings = type.split('-')[0] === 'v8' ? v8 : napi; - const methodName = 'callWith' + type.split('-')[1]; +function main({ n, engine, type }) { + const bindings = engine === 'v8' ? v8 : napi; + const methodName = 'callWith' + type; const fn = bindings[methodName]; if (fn) { - const args = getArgs(type); + const args = generateArgs(type); bench.start(); for (var i = 0; i < n; i++) { From f10939a7e9515cc40ff50eb86ba10ebc94bddf7a Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Wed, 4 Jul 2018 09:29:56 +0800 Subject: [PATCH 6/8] Fixing macro styling issue, trailing backslash alignment. --- benchmark/napi/function_args/napi_binding.c | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c index 643ab313093b89..17816849f474a6 100644 --- a/benchmark/napi/function_args/napi_binding.c +++ b/benchmark/napi/function_args/napi_binding.c @@ -189,18 +189,18 @@ static napi_value CallWithArguments(napi_env env, napi_callback_info info) { } -#define EXPORT_FUNC(name, func) \ - do { \ - napi_value func ## _v; \ - status = napi_create_function(env, \ - name, \ - NAPI_AUTO_LENGTH, \ - func, \ - NULL, \ - &func ## _v); \ - assert(status == napi_ok); \ +#define EXPORT_FUNC(name, func) \ + do { \ + napi_value func ## _v; \ + status = napi_create_function(env, \ + name, \ + NAPI_AUTO_LENGTH, \ + func, \ + NULL, \ + &func ## _v); \ + assert(status == napi_ok); \ status = napi_set_named_property(env, exports, name, func ## _v); \ - assert(status == napi_ok); \ + assert(status == napi_ok); \ } while (0); From 645f38e87553a43b5f56f692f7afc58c5b2654eb Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Wed, 4 Jul 2018 14:05:19 +0800 Subject: [PATCH 7/8] Change the local casual macro to a more formal one. --- benchmark/napi/function_args/napi_binding.c | 40 ++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c index 17816849f474a6..d537546584a05f 100644 --- a/benchmark/napi/function_args/napi_binding.c +++ b/benchmark/napi/function_args/napi_binding.c @@ -189,39 +189,39 @@ static napi_value CallWithArguments(napi_env env, napi_callback_info info) { } -#define EXPORT_FUNC(name, func) \ +#define EXPORT_FUNC(env, exports, name, func) \ do { \ - napi_value func ## _v; \ - status = napi_create_function(env, \ - name, \ + napi_status status; \ + napi_value js_func; \ + status = napi_create_function((env), \ + (name), \ NAPI_AUTO_LENGTH, \ - func, \ + (func), \ NULL, \ - &func ## _v); \ + &js_func); \ assert(status == napi_ok); \ - status = napi_set_named_property(env, exports, name, func ## _v); \ + status = napi_set_named_property((env), \ + (exports), (name), js_func); \ assert(status == napi_ok); \ } while (0); NAPI_MODULE_INIT() { - napi_status status; - - EXPORT_FUNC("callWithString", CallWithString); - EXPORT_FUNC("callWithLongString", CallWithString); + EXPORT_FUNC(env, exports, "callWithString", CallWithString); + EXPORT_FUNC(env, exports, "callWithLongString", CallWithString); - EXPORT_FUNC("callWithArray", CallWithArray); - EXPORT_FUNC("callWithLargeArray", CallWithArray); - EXPORT_FUNC("callWithHugeArray", CallWithArray); + EXPORT_FUNC(env, exports, "callWithArray", CallWithArray); + EXPORT_FUNC(env, exports, "callWithLargeArray", CallWithArray); + EXPORT_FUNC(env, exports, "callWithHugeArray", CallWithArray); - EXPORT_FUNC("callWithNumber", CallWithNumber); + EXPORT_FUNC(env, exports, "callWithNumber", CallWithNumber); - EXPORT_FUNC("callWithObject", CallWithObject); - EXPORT_FUNC("callWithTypedarray", CallWithTypedarray); + EXPORT_FUNC(env, exports, "callWithObject", CallWithObject); + EXPORT_FUNC(env, exports, "callWithTypedarray", CallWithTypedarray); - EXPORT_FUNC("callWith10Numbers", CallWithArguments); - EXPORT_FUNC("callWith100Numbers", CallWithArguments); - EXPORT_FUNC("callWith1000Numbers", CallWithArguments); + EXPORT_FUNC(env, exports, "callWith10Numbers", CallWithArguments); + EXPORT_FUNC(env, exports, "callWith100Numbers", CallWithArguments); + EXPORT_FUNC(env, exports, "callWith1000Numbers", CallWithArguments); return exports; } From 0f6b238dfd22c234a3257f8679f61422c90c750b Mon Sep 17 00:00:00 2001 From: Kenny Yuan Date: Thu, 5 Jul 2018 11:41:00 +0800 Subject: [PATCH 8/8] Use only one param alignment style in the helper macro. --- benchmark/napi/function_args/napi_binding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/napi/function_args/napi_binding.c b/benchmark/napi/function_args/napi_binding.c index d537546584a05f..6cb2f84bf58f64 100644 --- a/benchmark/napi/function_args/napi_binding.c +++ b/benchmark/napi/function_args/napi_binding.c @@ -201,7 +201,7 @@ static napi_value CallWithArguments(napi_env env, napi_callback_info info) { &js_func); \ assert(status == napi_ok); \ status = napi_set_named_property((env), \ - (exports), (name), js_func); \ + (exports), (name), js_func); \ assert(status == napi_ok); \ } while (0);