From 72f32282037a4fa948f73eb7f30a389b54f00d28 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Mon, 7 May 2018 00:15:00 +0200 Subject: [PATCH] lib: lazy loaded This makes sure the async hooks and more is only loaded in case it is actually necessary. PR-URL: https://github.com/nodejs/node/pull/20567 Reviewed-By: Gus Caplan Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel --- lib/internal/bootstrap/node.js | 12 ++- lib/internal/trace_events_async_hooks.js | 128 +++++++++++------------ 2 files changed, 71 insertions(+), 69 deletions(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 1aca1ea2374748..9183f4576b6e48 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -63,7 +63,17 @@ if (global.__coverage__) NativeModule.require('internal/process/write-coverage').setup(); - NativeModule.require('internal/trace_events_async_hooks').setup(); + + { + const traceEvents = process.binding('trace_events'); + const traceEventCategory = 'node,node.async_hooks'; + + if (traceEvents.categoryGroupEnabled(traceEventCategory)) { + NativeModule.require('internal/trace_events_async_hooks') + .setup(traceEvents, traceEventCategory); + } + } + if (process.config.variables.v8_enable_inspector) { NativeModule.require('internal/inspector_async_hook').setup(); diff --git a/lib/internal/trace_events_async_hooks.js b/lib/internal/trace_events_async_hooks.js index db38fe99adcc9c..011dc6bbead187 100644 --- a/lib/internal/trace_events_async_hooks.js +++ b/lib/internal/trace_events_async_hooks.js @@ -1,71 +1,63 @@ 'use strict'; -const trace_events = process.binding('trace_events'); -const async_wrap = process.binding('async_wrap'); -const async_hooks = require('async_hooks'); - -// Use small letters such that chrome://tracing groups by the name. -// The behavior is not only useful but the same as the events emitted using -// the specific C++ macros. -const BEFORE_EVENT = 'b'.charCodeAt(0); -const END_EVENT = 'e'.charCodeAt(0); - -// In trace_events it is not only the id but also the name that needs to be -// repeated. Since async_hooks doesn't expose the provider type in the -// non-init events, use a map to manually map the asyncId to the type name. -const typeMemory = new Map(); - -const trace_event_category = 'node,node.async_hooks'; - -// It is faster to emit trace_events directly from C++. Thus, this happens in -// async_wrap.cc. However, events emitted from the JavaScript API or the -// Embedder C++ API can't be emitted from async_wrap.cc. Thus they are -// emitted using the JavaScript API. To prevent emitting the same event -// twice the async_wrap.Providers list is used to filter the events. -const nativeProviders = new Set(Object.keys(async_wrap.Providers)); - -const hook = async_hooks.createHook({ - init(asyncId, type, triggerAsyncId, resource) { - if (nativeProviders.has(type)) return; - - typeMemory.set(asyncId, type); - trace_events.emit(BEFORE_EVENT, trace_event_category, - type, asyncId, - 'triggerAsyncId', triggerAsyncId, - 'executionAsyncId', async_hooks.executionAsyncId()); - }, - - before(asyncId) { - const type = typeMemory.get(asyncId); - if (type === undefined) return; - - trace_events.emit(BEFORE_EVENT, trace_event_category, - type + '_CALLBACK', asyncId); - }, - - after(asyncId) { - const type = typeMemory.get(asyncId); - if (type === undefined) return; - - trace_events.emit(END_EVENT, trace_event_category, - type + '_CALLBACK', asyncId); - }, - - destroy(asyncId) { - const type = typeMemory.get(asyncId); - if (type === undefined) return; - - trace_events.emit(END_EVENT, trace_event_category, - type, asyncId); - - // cleanup asyncId to type map - typeMemory.delete(asyncId); - } -}); - - -exports.setup = function() { - if (trace_events.categoryGroupEnabled(trace_event_category)) { - hook.enable(); - } +exports.setup = function(traceEvents, traceEventCategory) { + const async_wrap = process.binding('async_wrap'); + const async_hooks = require('async_hooks'); + + // Use small letters such that chrome://tracing groups by the name. + // The behavior is not only useful but the same as the events emitted using + // the specific C++ macros. + const BEFORE_EVENT = 'b'.charCodeAt(0); + const END_EVENT = 'e'.charCodeAt(0); + + // In traceEvents it is not only the id but also the name that needs to be + // repeated. Since async_hooks doesn't expose the provider type in the + // non-init events, use a map to manually map the asyncId to the type name. + const typeMemory = new Map(); + + // It is faster to emit traceEvents directly from C++. Thus, this happens + // in async_wrap.cc. However, events emitted from the JavaScript API or the + // Embedder C++ API can't be emitted from async_wrap.cc. Thus they are + // emitted using the JavaScript API. To prevent emitting the same event + // twice the async_wrap.Providers list is used to filter the events. + const nativeProviders = new Set(Object.keys(async_wrap.Providers)); + + async_hooks.createHook({ + init(asyncId, type, triggerAsyncId, resource) { + if (nativeProviders.has(type)) return; + + typeMemory.set(asyncId, type); + traceEvents.emit(BEFORE_EVENT, traceEventCategory, + type, asyncId, + 'triggerAsyncId', triggerAsyncId, + 'executionAsyncId', async_hooks.executionAsyncId()); + }, + + before(asyncId) { + const type = typeMemory.get(asyncId); + if (type === undefined) return; + + traceEvents.emit(BEFORE_EVENT, traceEventCategory, + type + '_CALLBACK', asyncId); + }, + + after(asyncId) { + const type = typeMemory.get(asyncId); + if (type === undefined) return; + + traceEvents.emit(END_EVENT, traceEventCategory, + type + '_CALLBACK', asyncId); + }, + + destroy(asyncId) { + const type = typeMemory.get(asyncId); + if (type === undefined) return; + + traceEvents.emit(END_EVENT, traceEventCategory, + type, asyncId); + + // cleanup asyncId to type map + typeMemory.delete(asyncId); + } + }).enable(); };