summaryrefslogtreecommitdiff
path: root/benchmark
diff options
context:
space:
mode:
authorGabriel Schulhof <gabriel.schulhof@intel.com>2019-09-05 18:38:19 -0700
committerGabriel Schulhof <gabriel.schulhof@intel.com>2019-10-13 00:07:43 -0700
commit53ca0b9ae145c430842bf78e553e3b6cbd2823aa (patch)
treee7eb7372e2bd4cc16deeaa7310417f024231ffd6 /benchmark
parentfce1a5198a89e8f62ea2d093e01971db46da9bf5 (diff)
downloadandroid-node-v8-53ca0b9ae145c430842bf78e553e3b6cbd2823aa.tar.gz
android-node-v8-53ca0b9ae145c430842bf78e553e3b6cbd2823aa.tar.bz2
android-node-v8-53ca0b9ae145c430842bf78e553e3b6cbd2823aa.zip
src: render N-API weak callbacks as cleanup hooks
Since worker threads are complete Node.js environments, including the ability to load native addons, and since those native addons can allocate resources to be freed when objects go out of scope, and since, upon worker thread exit, the engine does not invoke the weak callbacks responsible for freeing resources which still have references, this modification introduces tracking for weak references such that a list of outstanding weak references is maintained. This list is traversed during environment teardown. The callbacks for the remaining weak references are called. This change is also relevant for Node.js embedder scenarios, because in those cases the process also outlives the `node::Environment` and therefore weak callbacks should also be rendered as environment cleanup hooks to ensure proper cleanup after native addons. This changes introduces the means by which this can be accomplished. A benchmark is included which measures the time it takes to execute the weak reference callback for a given number of weak references. Re: https://github.com/tc39/proposal-weakrefs/issues/125#issuecomment-535832130 PR-URL: https://github.com/nodejs/node/pull/28428 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Diffstat (limited to 'benchmark')
-rw-r--r--benchmark/napi/ref/addon.c82
-rw-r--r--benchmark/napi/ref/binding.gyp10
-rw-r--r--benchmark/napi/ref/index.js17
3 files changed, 109 insertions, 0 deletions
diff --git a/benchmark/napi/ref/addon.c b/benchmark/napi/ref/addon.c
new file mode 100644
index 0000000000..3fb8de603d
--- /dev/null
+++ b/benchmark/napi/ref/addon.c
@@ -0,0 +1,82 @@
+#include <stdlib.h>
+#define NAPI_EXPERIMENTAL
+#include <node_api.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(napi_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;
+}
diff --git a/benchmark/napi/ref/binding.gyp b/benchmark/napi/ref/binding.gyp
new file mode 100644
index 0000000000..d641e99efd
--- /dev/null
+++ b/benchmark/napi/ref/binding.gyp
@@ -0,0 +1,10 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'addon',
+ 'sources': [
+ 'addon.c'
+ ]
+ }
+ ]
+}
diff --git a/benchmark/napi/ref/index.js b/benchmark/napi/ref/index.js
new file mode 100644
index 0000000000..3a5e198827
--- /dev/null
+++ b/benchmark/napi/ref/index.js
@@ -0,0 +1,17 @@
+'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();
+ while (addon.count < n) {
+ callNewWeak();
+ }
+ bench.end(n);
+}