-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inspector: enable async stack traces
Implement a special async_hooks listener that forwards information about async tasks to V8Inspector asyncTask* API, thus enabling DevTools feature "async stack traces". The feature is enabled only on 64bit platforms due to a technical limitation of V8 Inspector: inspector uses a pointer as a task id, while async_hooks use 64bit numbers as ids. To avoid performance penalty of async_hooks when not debugging, the new listener is enabled only when the process enters a debug mode: - When the process is started with `--inspect` or `--inspect-brk`, the listener is enabled immediately and async stack traces lead all the way to the first tick of the event loop. - When the debug mode is enabled via SIGUSR1 or `_debugProcess()`, the listener is enabled together with the debugger. As a result, only async operations started after the signal was received will be correctly observed and reported to V8 Inspector. For example, a `setInterval()` called in the first tick of the event will not be shown in the async stack trace when the callback is invoked. This behaviour is consistent with Chrome DevTools. Last but not least, this commit fixes handling of InspectorAgent's internal property `enabled_` to ensure it's set back to `false` after the debugger is deactivated (typically via `process._debugEnd()`). Fixes: #11370 PR-URL: #13870 Reviewed-by: Timothy Gu <[email protected]> Reviewed-by: Anna Henningsen <[email protected]>
- Loading branch information
1 parent
e0dccd0
commit 9836254
Showing
17 changed files
with
656 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
'use strict'; | ||
|
||
const { createHook } = require('async_hooks'); | ||
const inspector = process.binding('inspector'); | ||
const config = process.binding('config'); | ||
|
||
if (!inspector || !inspector.asyncTaskScheduled) { | ||
exports.setup = function() {}; | ||
return; | ||
} | ||
|
||
const hook = createHook({ | ||
init(asyncId, type, triggerAsyncId, resource) { | ||
// It's difficult to tell which tasks will be recurring and which won't, | ||
// therefore we mark all tasks as recurring. Based on the discussion | ||
// in https://github.com/nodejs/node/pull/13870#discussion_r124515293, | ||
// this should be fine as long as we call asyncTaskCanceled() too. | ||
const recurring = true; | ||
inspector.asyncTaskScheduled(type, asyncId, recurring); | ||
}, | ||
|
||
before(asyncId) { | ||
inspector.asyncTaskStarted(asyncId); | ||
}, | ||
|
||
after(asyncId) { | ||
inspector.asyncTaskFinished(asyncId); | ||
}, | ||
|
||
destroy(asyncId) { | ||
inspector.asyncTaskCanceled(asyncId); | ||
}, | ||
}); | ||
|
||
function enable() { | ||
if (config.bits < 64) { | ||
// V8 Inspector stores task ids as (void*) pointers. | ||
// async_hooks store ids as 64bit numbers. | ||
// As a result, we cannot reliably translate async_hook ids to V8 async_task | ||
// ids on 32bit platforms. | ||
process.emitWarning( | ||
'Warning: Async stack traces in debugger are not available ' + | ||
`on ${config.bits}bit platforms. The feature is disabled.`, | ||
{ | ||
code: 'INSPECTOR_ASYNC_STACK_TRACES_NOT_AVAILABLE', | ||
}); | ||
} else { | ||
hook.enable(); | ||
} | ||
} | ||
|
||
function disable() { | ||
hook.disable(); | ||
} | ||
|
||
exports.setup = function() { | ||
inspector.registerAsyncHook(enable, disable); | ||
|
||
if (inspector.isEnabled()) { | ||
// If the inspector was already enabled via --inspect or --inspect-brk, | ||
// the we need to enable the async hook immediately at startup. | ||
enable(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.