Skip to content

Commit 1274aad

Browse files
committed
async_hooks: optimize fast-path promise hook for ALS
Remove unnecessary native-to-JS code switches in fast-path for PromiseHooks. Those switches happen even if a certain type of hook (say, before) is not installed, which may lead to sub-optimal performance in the AsyncLocalStorage scenario, i.e. when there is only an init hook.
1 parent e8d7fed commit 1274aad

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

benchmark/async_hooks/promises.js

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const tests = {
1919
promiseResolve() {},
2020
destroy() {}
2121
}).enable();
22+
},
23+
enabledWithInitOnly() {
24+
hook = createHook({
25+
init() {}
26+
}).enable();
2227
}
2328
};
2429

@@ -27,6 +32,7 @@ const bench = common.createBenchmark(main, {
2732
asyncHooks: [
2833
'enabled',
2934
'enabledWithDestroy',
35+
'enabledWithInitOnly',
3036
'disabled',
3137
]
3238
});

src/async_wrap.cc

+59-7
Original file line numberDiff line numberDiff line change
@@ -231,19 +231,18 @@ PromiseWrap* PromiseWrap::New(Environment* env,
231231

232232
// Skip for init events
233233
if (silent) {
234-
Local<Value> maybeAsyncId = promise
234+
Local<Value> maybe_async_id = promise
235235
->Get(context, env->async_id_symbol())
236236
.ToLocalChecked();
237237

238-
Local<Value> maybeTriggerAsyncId = promise
238+
Local<Value> maybe_trigger_async_id = promise
239239
->Get(context, env->trigger_async_id_symbol())
240240
.ToLocalChecked();
241241

242-
if (maybeAsyncId->IsNumber() && maybeTriggerAsyncId->IsNumber()) {
243-
double asyncId = maybeAsyncId->NumberValue(context).ToChecked();
244-
double triggerAsyncId = maybeTriggerAsyncId->NumberValue(context)
245-
.ToChecked();
246-
return new PromiseWrap(env, obj, asyncId, triggerAsyncId);
242+
if (maybe_async_id->IsNumber() && maybe_trigger_async_id->IsNumber()) {
243+
double async_id = maybe_async_id.As<Number>()->Value();
244+
double trigger_async_id = maybe_trigger_async_id.As<Number>()->Value();
245+
return new PromiseWrap(env, obj, async_id, trigger_async_id);
247246
}
248247
}
249248

@@ -320,6 +319,59 @@ static void FastPromiseHook(PromiseHookType type, Local<Promise> promise,
320319
Environment* env = Environment::GetCurrent(context);
321320
if (env == nullptr) return;
322321

322+
if (type == PromiseHookType::kBefore &&
323+
env->async_hooks()->fields()[AsyncHooks::kBefore] == 0) {
324+
Local<Value> maybe_async_id;
325+
if (!promise->Get(context, env->async_id_symbol())
326+
.ToLocal(&maybe_async_id)) {
327+
return;
328+
}
329+
330+
Local<Value> maybe_trigger_async_id;
331+
if (!promise->Get(context, env->trigger_async_id_symbol())
332+
.ToLocal(&maybe_trigger_async_id)) {
333+
return;
334+
}
335+
336+
if (maybe_async_id->IsNumber() && maybe_trigger_async_id->IsNumber()) {
337+
double async_id = maybe_async_id.As<Number>()->Value();
338+
double trigger_async_id = maybe_trigger_async_id.As<Number>()->Value();
339+
env->async_hooks()->push_async_context(
340+
async_id, trigger_async_id, promise);
341+
}
342+
343+
return;
344+
}
345+
346+
if (type == PromiseHookType::kAfter &&
347+
env->async_hooks()->fields()[AsyncHooks::kAfter] == 0) {
348+
Local<Value> maybe_async_id;
349+
if (!promise->Get(context, env->async_id_symbol())
350+
.ToLocal(&maybe_async_id)) {
351+
return;
352+
}
353+
354+
if (maybe_async_id->IsNumber()) {
355+
double async_id = maybe_async_id.As<Number>()->Value();
356+
if (env->execution_async_id() == async_id) {
357+
// This condition might not be true if async_hooks was enabled during
358+
// the promise callback execution.
359+
env->async_hooks()->pop_async_context(async_id);
360+
}
361+
}
362+
363+
return;
364+
}
365+
366+
if (type == PromiseHookType::kResolve &&
367+
env->async_hooks()->fields()[AsyncHooks::kPromiseResolve] == 0) {
368+
return;
369+
}
370+
371+
// Getting up to this point means either init type or
372+
// that there are active hooks of another type.
373+
// In both cases fast-path JS hook should be called.
374+
323375
Local<Value> argv[] = {
324376
Integer::New(env->isolate(), ToAsyncHooksType(type)),
325377
promise,

0 commit comments

Comments
 (0)