-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
async-hooks: add trace events to AsyncWrap #14347
Conversation
This doesn't integrate with the Embedder API. The JavaScript Embedder API may be tricky, but I think it would be worth looking into integrating with the C++ Embedder API. Also, were there not a trace-events related to the callbacks? |
@AndreasMadsen I agree that integrating with the embedder apis would be good. C++ should be achievable now (maybe in a follow on PR) and JS embedder API could be accomplished once there is a JS tracing API (nodejs/node-eps#48). Which callbacks were you referring to in "Also, were there not a trace-events related to the callbacks?"? |
The overlap between this and the C++ Embedding API is too great, I think we should just do it in this PR.
This informs about the |
@AndreasMadsen Looking at the C++ Embedding API, it seems that the corresponding points are For |
Correct. That is why I'm thinking the overlap is too great.
I see. That might be problematic, for /cc @nodejs/async_hooks |
} | ||
|
||
|
||
AsyncWrap::~AsyncWrap() { | ||
switch (provider_type()) { | ||
#define V(PROVIDER) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are places where this will fail:
HTTPParser
whenrequire('_http_common').freeParser()
is called. An internal pool of parsers is created and every time one is used it's assigned a new async id. To get around thisTRACE_EVENT_NESTABLE_ASYNC_BEGIN0
needs to be placed inParser::Reinitialize()
(src/node_http_parser.cc
) andTRACE_EVENT_NESTABLE_ASYNC_END0
at theemitDestroy()
call infreeParser()
(lib/_http_common.js
).- Every
Timeout
andImmediate
, since they're all pseudo async resources (depending on theTimerWrap
to fire). Since they depend on theTimerWrap
there will still be an associated async id, just not the greater detail of each JS object.
Neither of these would be a blocker for me landing this PR. Just note that (1) will not have the same async ids going in as it does going out. Also I would suggest we exclude nextTick()
calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand, currently, no trace events will be reported for httpparser or the js side of timers. Is there a chance for any malformed events (start without end, etc)? Why should nextTick
be excluded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand, currently, no trace events will be reported for httpparser
You will get an init()
every time an http node::Parser
is initialized, and you'll get before()
/after()
for that one as well, but you won't get a destroy()
for that parser if it's placed in the freeParser()
pool.
When the Parser
is reused a new async_id
is assigned, then you'll get a before()
/after()
call for the async_id
that hasn't had init()
called yet. Creating a broken call graph.
The init()
call can be fixed by placing TRACE_EVENT_NESTABLE_ASYNC_BEGIN0
in node::Parser::Reinitialize()
, but there's no way to track when the node::Parser
instance has been placed in the pool from C++. So it would require a JS call.
The freeParser()
code path isn't hot, so it's not unreasonable to put a JS call in there to notify C++ that the parser is done and it can emit destroy()
.
@AndreasMadsen I think adding one begin/end pair to |
This will allow trace event to record timing information for all asynchronous operations that are observed by AsyncWrap.
I think that is okay, there isn't much else we can do. |
+cc @danielkhan |
break; | ||
NODE_ASYNC_PROVIDER_TYPES(V) | ||
#undef V | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to place these switch
statements into a conditional that checks whether trace events are enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could expose a check for whether trace events are enabled if necessary but each of these macros starts by running such a check and I would guess the overhead of the switch alone would be minimal.
@AndreasMadsen @trevnorris Having added the trace events for before/after, I wonder whether measuring synchronous callback execution time provides value. What do you think about adding a begin event in /cc @lpy in case he has suggestions on naming or event placement. |
This needs a rebase |
Ping @matthewloring |
I agree, that measuring the time between JS Embedder API It appears that the This also solves the issue with the C++ Embedder API and the missing event name, since it will be trivial for us to track that using a basic To avoid unnecessary C++ binding calls from JavaScript, we can filter the calls using |
@AndreasMadsen .. since you're looking into this area, a related effort would be implementing the |
@jasnell How is it relevant and do you know where I can find the documentation? |
@matthewloring I have rebased this in AndreasMadsen@b3d025e. For some reason, I get a segmentation fault when My commit also fixes the HTTP_PARSER issue and removes the trace_event integration with the C++ Embedder API. I plan to setup the C++ Embedder API and JavaScript Embedder API as I suggested, but I want to benchmark the current implementation first. |
@AndreasMadsen ... not directly related to this specific PR. There aren't any docs as far as I know. The Macros are there but they are currently not implemented. We can discuss this separately. |
@AndreasMadsen I am not able to reproduce a segfault with your rebased patch. What was the specific code you were trying to run? |
@matthewloring simply running |
The original |
Properly the situation is different. Besides ignoring the events we don't really have another option. |
@AndreasMadsen What platform are you running on? I am able to run the repl without a crash on my mac. |
@matthewloring also mac :( I will try with a clean build. If that doesn't work I will make a PR and run the CI. |
Closing in favor of #15538. |
This will allow trace event to record timing information for all
asynchronous operations that are observed by AsyncWrap.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
async-hooks, tracing